SSL между ALB и приложением

Эта программа имеет четко определенное поведение и демонстрирует ошибку g ++.

Единственная сомнительная часть времени выполнения - во время инструкции (*f)();. Поведение этой линии можно разделить по частям. Ниже приведены номера стандартных разделов: N3485; извините, если некоторые из них не соответствуют C ++ 11.

*f - это просто встроенный унарный оператор на необработанном указателе на тип класса. Здесь нет проблем. Единственной другой оценкой является выражение функции-вызова (*f)(), которое вызывает void std::function<void()>::operator() const. Тогда это полное выражение является отброшенным значением.

20.8.11.2.4:

R operator()(ArgTypes... args) const

Эффекты: INVOKE (obj, std::forward<ArgTypes>(args)..., R) где obj - целевой объект *this.

(Я заменил «f» в стандарте на «obj», чтобы уменьшить путаницу с main ] f.)

Здесь obj является копией лямбда-объекта, ArgTypes является пустым пакетом параметров из специализации std::function<void()>, а R - void .

Псевдомакрокоманда INVOKE определена в 20.8.2. Поскольку тип obj не является указателем на член, INVOKE (obj, void) определяется как obj(), неявно преобразованный в void.

5.1.2p5:

Тип замыкания для lambda-expression имеет общедоступный оператор вызова функции inline ...

... с точно описанным объявлением. В этом случае это оказывается void operator() const. И его определение точно описано также:

5.1.2p7:

Компонентный оператор лямбда-выражения дает функцию-тело оператора вызова функции, но для целей поиска имени, определения типа и значения this и преобразования id-выражений , относящихся к нестатические члены класса в выражения доступа к членам класса, используя (*this), составной оператор рассматривается в контексте лямбда-выражения .

5.1.2p14:

Для каждого объекта, захваченного копией, в типе замыкания объявляется неназванный нестатический элемент данных.

5.1.2p17:

Каждое id-выражение , которое является нечетным использованием объекта, захваченного копией, преобразуется в доступ к соответствующему неназванному элементу данных из тип закрытия.

Таким образом, оператор вызова лямбда-функции должен быть эквивалентен:

void __lambda_type::operator() const {
    delete __unnamed_member_f;
}

(где я изобрел некоторые имена для неназванного лямбда-типа и неназванного элемента данных.)

Единственный оператор этого оператора вызова, конечно, эквивалентен delete (*this).__unnamed_member_f;. Итак, мы имеем:

  • Разъем размытия operator* в унарной operator*)
  • Выражение доступа к членству
  • Вычисление значения (aka lvalue- to-rvalue) для субобъекта-члена
  • Сжатие delete выражение Invokes std::function<void()>::~function() Вызывает void operator delete(void*)

И, наконец, в 5.3.5p4:

cast-expression в delete-expression будет оцениваться ровно один раз.

( Здесь g ++ ошибается, делая второе вычисление значения в подобъекте элемента между вызовом деструктора и функцией освобождения.)

Этот код не может вызывать каких-либо других вычислений или побочных эффектов после выражения delete .

Существуют некоторые допуски для поведения, определяемого реализацией в лямбда-типах и lam bda, но ничто не влияет на что-либо выше:

5.1.2p3:

Реализация может определять тип закрытия иначе, чем описано ниже, если это не изменяет наблюдаемое поведение программы, отличное от изменения:

  • размера и / или выравнивания типа замыкания,
  • , является ли тип замыкания тривиально копируемым,
  • является ли тип замыкания стандартным классом макета или
  • , является ли тип замыкания классом POD.
0
задан OK999 16 January 2019 в 18:02
поделиться