8 Expressions [expr]

8.3 Unary expressions [expr.unary]

Выражения с унарными операторами группируются справа налево.

unary-expression:
	postfix-expression
	++ cast-expression
	-- cast-expression
	unary-operator cast-expression
	sizeof unary-expression
	sizeof ( type-id )
	sizeof ... ( identifier )
	alignof ( type-id )
	noexcept-expression
	new-expression
	delete-expression

unary-operator: one of
	*  &  +  -  !  ~

8.3.1 Unary operators [expr.unary.op]

Унарный * оператор выполняет indirection: выражение, к которому он применяется, должно быть указателем на тип объекта или указателем на тип функции, а результатом является lvalue, относящееся к объекту или функции, на которые указывает выражение. Если тип выражения - «указатель на T», тип результата - «T». [ Косвенное указание на неполный тип (кроме ) допустимо. Полученное таким образом lvalue можно использовать ограниченными способами (например, для инициализации ссылки); это lvalue нельзя преобразовывать в prvalue, см . ]Note: cv void [conv.lval]end note

Результатом каждого из следующих унарных операторов является prvalue.

Результатом унарного & оператора является указатель на его операнд. Операнд должен быть lvalue или a qualified-id. Если операнд представляет собой qualified-idименование нестатического или вариантного члена m некоторого класса C с типом T, результат имеет тип «указатель на член класса C типа T» и является обозначением prvalue C​::​m. В противном случае, если тип выражения - это T, результат имеет тип «указатель на T» и является значением prvalue, которое является адресом назначенного объекта ([intro.memory]) или указателем на назначенную функцию. [ Note: В частности, адрес объекта типа «cv T» - «указатель на cv T» с той же квалификацией cv. ] В целях арифметики указателя ( ) и сравнения ( , ) объект, не являющийся элементом массива, адрес которого берется таким образом, считается принадлежащим к массиву с одним элементом типа . [ end note[expr.add][expr.rel] [expr.eq] TExample:

struct A { int i; };
struct B : A { };
... &B::i ...       // has type int A​::​*
int a;
int* p1 = &a;
int* p2 = p1 + 1;   // defined behavior
bool b = p2 > p1;   // defined behavior, with value true

end example] [ Note: Указатель на член, сформированный из mutable нестатического члена данных ([dcl.stc]), не отражает mutable спецификатор, связанный с нестатическим членом данных. ]end note

Указатель на член формируется только тогда, когда используется явное значение, & а его операнд qualified-idне заключен в круглые скобки. [ Note: То есть выражение &(qualified-id), в котором qualified-idзаключено в круглые скобки, не образует выражение типа «указатель на член». Также нет qualified-id, потому что не существует неявного преобразования из a qualified-idдля нестатической функции-члена в тип «указатель на функцию-член», как из lvalue типа функции в тип «указатель на функцию» ([conv.func]). Также нет &unqualified-id указателя на член, даже в рамках unqualified-idкласса. ]end note

Если & применяется к lvalue неполного типа класса и объявляется полный тип, не указывается operator&(), имеет ли оператор встроенное значение или вызывается операторная функция. Операнд & не должен быть битовым полем.

Адрес overloaded function может быть взят только в контексте, который однозначно определяет, к какой версии перегруженной функции относится ссылка (см [over.over]. Раздел "Ресурсы" ). [ Note: Поскольку контекст может определять, является ли операнд статической или нестатической функцией-членом, контекст также может влиять на то, имеет ли выражение тип «указатель на функцию» или «указатель на функцию-член». ]end note

Операнд унарного + оператора должен иметь арифметический, перечисление без области действия или тип указателя, а результатом является значение аргумента. Целостное продвижение выполняется для целых или перечислимых операндов. Тип результата - это тип продвинутого операнда.

Операнд унарного - оператора должен иметь арифметический тип или тип перечисления с незаданной областью, а результатом является отрицание его операнда. Целостное продвижение выполняется для целых или перечислимых операндов. Отрицательное значение беззнаковой величины вычисляется путем вычитания ее значения из 2n, где n - количество бит в продвинутом операнде. Тип результата - это тип продвинутого операнда.

Операнд логической операции отрицания ! является contextually converted to bool; его значение равно, true если преобразованный операнд есть, false и в false противном случае. Тип результата bool.

Операнд ~ должен иметь целочисленный или незадействованный перечислимый тип; результатом является дополнение до единиц своего операнда. Выполняются комплексные акции. Тип результата - это тип продвинутого операнда. В грамматике возникает двусмысленность, когда ~ следует class-nameили decltype-specifier. Неоднозначность разрешается путем рассмотрения ~ как унарного оператора дополнения, а не как начало unqualified-id именования деструктора. [ Note: Поскольку грамматика не разрешает оператору следовать за ., ->или ​::​ токенами, ~ за которым следует class-nameили decltype-specifierв выражении доступа к члену, либо qualified-idоднозначно анализируется как имя деструктора. ]end note

8.3.2 Increment and decrement [expr.pre.incr]

Операнд префикса изменяется добавлением . Операнд должен быть изменяемым значением. Тип операнда должен быть арифметическим типом, отличным от полностью определенного типа объекта, или указателем на него. Результат - обновленный операнд; это lvalue, и это битовое поле, если операнд является битовым полем. Выражение эквивалентно . [ См. Обсуждения и информацию о преобразованиях. ] ++ 1 cv bool ++x x+=1Note: addition assignment operators end note

Операнд префикса -- изменяется вычитанием 1. Требования к операнду префикса -- и свойствам его результата в остальном такие же, как и у префикса ++. [ Note: Для постфиксного увеличения и уменьшения см [expr.post.incr].. ]end note

8.3.3 Sizeof [expr.sizeof]

sizeof Оператор дает число байтов в объекте представления операнда. Операнд может быть выражением unevaluated operandили заключенным в скобки type-id. Оператор не должен быть применен к выражению , которое имеет функцию или неполный тип, в скобках название таких типов, или к glvalue , что обозначает битовое поле. , и есть . Результат применения к любому другому определяется реализацией. [ В частности, , , , и являются реализация. ] [ См. Определение и определение . ] sizeof sizeof(char) sizeof(signed char) sizeof(unsigned char) 1sizeof fundamental type Note: sizeof(bool) sizeof(char16_­t)sizeof(char32_­t) sizeof(wchar_­t) 77 end noteNote: [intro.memory] byte [basic.types] object representationend note

При применении к ссылке или ссылочному типу результатом является размер ссылочного типа. При применении к классу результатом является количество байтов в объекте этого класса, включая любые отступы, необходимые для размещения объектов этого типа в массиве. Размер a most derived class должен быть больше нуля. Результатом применения sizeof к подобъекту базового класса является размер типа базового класса. При применении к массиву результатом является общее количество байтов в массиве. Это означает, что размер массива элементов в несколько раз превышает размер элемента.78 n n

sizeof Оператор может быть применен к указателю на функцию, но не должен применяться непосредственно к функции.

В lvalue-to-rvalue, array-to-pointerи function-to-pointer стандартные преобразования не применяется к операнду sizeof. Если операнд является prvalue, temporary materialization conversion применяется.

Идентификатор в sizeof... выражении должен называть пакет параметров. sizeof... Оператор дает количество аргументов , предусмотренным для параметра пакета identifier. sizeof... Выражение является pack expansion. [Example:

template<class... Types>
struct count {
  static const std::size_t value = sizeof...(Types);
};

end example]

Результат sizeof и sizeof... является константой типа std​::​size_­t. [ определяется в стандартном заголовке ( , ). ]Note: std​::​size_­t <cstddef> [cstddef.syn] [support.types.layout]end note

sizeof(bool) не требуется 1.

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

8.3.4 New [expr.new]

Эти new-expressionпопытки создать объект из type-idили new-type-idк которому она применяется. Тип этого объекта - allocated type. Этот тип должен быть полный тип объекта, но не абстрактный тип класса или их массив ([intro.object], [basic.types], [class.abstract]). [ Note: Поскольку ссылки не являются объектами, ссылки не могут быть созданы с помощью new-expressions. ] [ Может быть резюме квалифицированных типа, в этом случае объект , созданный имеет резюме квалифицированных типа. ]end noteNote: type-idnew-expressionend note

new-expression:
	::opt new new-placementopt new-type-id new-initializeropt 
	::opt new new-placementopt ( type-id ) new-initializeropt

new-placement:
	( expression-list )
new-type-id:
	type-specifier-seq new-declaratoropt
new-declarator:
	ptr-operator new-declaratoropt 
	noptr-new-declarator
noptr-new-declarator:
	[ expression ] attribute-specifier-seqopt
	noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt
new-initializer:
	( expression-listopt )
	braced-init-list

Объекты , созданные new-expressionимеют dynamic storage duration. [ Время существования такой сущности не обязательно ограничивается областью, в которой она создана. ] Если сущность не является объектом массива, возвращает указатель на созданный объект. Если это массив, возвращает указатель на начальный элемент массива.Note: end notenew-expressionnew-expression

Если a placeholder type появляется в type-specifier-seqa new-type-idили type-ida new-expression, выделенный тип выводится следующим образом: Пусть init будет the new-initializer, если есть, и T будет the new-type-idor type-idof the new-expression, тогда выделенный тип - это тип, выведенный для переменной x в изобретенном объявлении ([dcl.spec.auto]) :

T x init ;

[Example:

new auto(1);                    // allocated type is int
auto x = new auto('a');         // allocated type is char, x is of type char*

template<class T> struct A { A(T, T); };
auto y = new A{1, 2};           // allocated type is A<int>

end example]

В new-type-ida new-expression- самая длинная возможная последовательность new-declarators. [ Note: Это предотвращает неоднозначность между описателем операторами &, &&, *и [] и их экспрессиями аналогами. ] [end noteExample:

new int * i;                    // syntax error: parsed as (new int*) i, not as (new int)*i

Это * декларатор указателя, а не оператор умножения. ]end example

[ Скобки в из может иметь неожиданные последствия. [Note: new-type-idnew-expressionExample:

new int(*[10])();               // error

неправильно сформирован, потому что привязка

(new int) (*[10])();            // error

Вместо этого явно заключенная в скобки версия new оператора может использоваться для создания объектов compound types:

new (int (*[10])());

выделяет массив 10 указателей на функции (без аргументов и с возвратом int). ] ]end exampleend note

Когда выделенный объект является массивом (то есть используется noptr-new-declaratorсинтаксис или new-type-idили type-idобозначает тип массива), new-expressionвыдает указатель на начальный элемент (если есть) массива. [ Note: Оба new int и new int[10] имеют тип, int* а тип new int[i][10] - это ] В a принадлежит к соответствующему типу массива. int (*)[10] end noteattribute-specifier-seqnoptr-new-declarator

Каждый constant-expressionэлемент a noptr-new-declaratorдолжен бытьconverted constant expression типа a std​::​size_­t и иметь строго положительное значение. Объект expressionв a noptr-new-declaratorнеявно преобразуется в std​::​size_­t. [ Example: Принимая во внимание определение int n = 42, new float[n][5] правильно сформирован (потому что n это expressionв А noptr-new-declarator), но new float[5][n] плохо сформированные (потому что n это не выражение постоянной). ]end example

В expressiona noptr-new-declaratorошибочно, если:

  • выражение неклассового типа и его значение перед преобразованием в std​::​size_­t меньше нуля;

  • выражение относится к классу и его значение до применения второго стандартного преобразования ([over.ics.user])79 меньше нуля;

  • его значение таково, что размер выделенного объекта будет превышать размер, определенный реализацией limit; или

  • new-initializerявляется braced-init-listи количество элементов массива , для которых предусмотрены инициализаторов (включая завершающий '\0' в string literal) превышает количество элементов , чтобы инициализировать.

Если expressionпосле преобразования в std​::​size_­t:

  • если expressionявляется основным постоянным выражением, программа имеет неправильный формат;

  • в противном случае функция распределения не вызывается; вместо

    • если функция выделения, которая должна была быть вызвана, имеет спецификацию исключения, не вызывающего выброса ([except.spec]), значением new-expression является значение нулевого указателя требуемого типа результата;

    • в противном случае new-expressionзавершается выдача исключения типа, который соответствует типу handler ([except.handle]) std​::​bad_­array_­new_­length.

Когда значение expressionравно нулю, вызывается функция выделения для выделения массива без элементов.

A new-expressionможет получить хранилище для объекта, вызвав функцию распределения ([basic.stc.dynamic.allocation]). Если new-expressionзавершается выдачей исключения, он может освободить хранилище, вызвав a deallocation function. Если выделенный тип не является массивом, имя функции выделения - это, а имя функции освобождения - . Если выделенный тип является типом массива, имя функции распределения - это, а имя функции освобождения - . [ Реализация должна дать определения по умолчанию для глобальных функций распределения ( , , ). Программа на C ++ может предоставлять альтернативные определения этих функций ( ) и / или версий для конкретных классов ( ). Набор функций выделения и освобождения, который может быть вызван a, может включать в себя функции, которые не выполняют выделение или освобождение; например, см . ]operator new operator deleteoperator new[]operator delete[]Note: [basic.stc.dynamic] [new.delete.single] [new.delete.array][replacement.functions][class.free]new-expression [new.delete.placement]end note

Если new-expressionначинается с унарного ​::​ оператора, имя функции распределения ищется в глобальной области. В противном случае, если выделенный тип является типом класса T или его массивом, имя функции распределения ищется в области видимости T. Если этот поиск не может найти имя или если выделенный тип не является типом класса, имя функции распределения ищется в глобальной области.

Реализации разрешено опускать вызов заменяемой функции глобального распределения ([new.delete.single], [new.delete.array]). Когда это происходит, хранилище вместо этого предоставляется реализацией или предоставляется путем расширения выделения другой new-expression. Реализация может расширить выделение a, new-expression e1 чтобы предоставить хранилище для a, new-expression e2 если бы было верно следующее, если бы выделение не было расширено:

  • оценка e1 выполняется до оценки e2, и

  • e2 оценивается всякий раз, когда e1 получает память, и

  • оба e1 и e2 вызывают одну и ту же заменяемую функцию глобального распределения, и

  • если функция распределения, вызванная e1 и e2 выбрасывает, любые исключения, возникшие при оценке любого из e1 или e2 , будут сначала перехвачены в том же обработчике, и

  • значения указателя, созданные e1 и e2 являются операндами для оценки delete-expressions, и

  • оценка e2 выполняется перед оценкой того, delete-expressionчей операнд является значением указателя, созданным e1.

[Example:

  void mergeable(int x) {
    // These allocations are safe for merging:
    std::unique_ptr<char[]> a{new (std::nothrow) char[8]};
    std::unique_ptr<char[]> b{new (std::nothrow) char[8]};
    std::unique_ptr<char[]> c{new (std::nothrow) char[x]};

    g(a.get(), b.get(), c.get());
  }

  void unmergeable(int x) {
    std::unique_ptr<char[]> a{new char[8]};
    try {
      // Merging this allocation would change its catch handler.
      std::unique_ptr<char[]> b{new char[x]};
    } catch (const std::bad_alloc& e) {
      std::cerr << "Allocation failed: " << e.what() << std::endl;
      throw;
    }
  }

end example]

Когда a new-expressionвызывает функцию выделения и это выделение не было расширено, он new-expressionпередает запрошенный объем пространства в функцию выделения в качестве первого аргумента типа std​::​size_­t. Этот аргумент должен быть не меньше размера создаваемого объекта; он может быть больше размера создаваемого объекта, только если объект является массивом. Для массивов char, unsigned charи std​::​byte, разность между результатом new-expressionи адресом , возвращаемым функцией распределения должна быть целым кратной строжайшим фундаментальным alignment requirement любым типа объекта, размер которого не больше , чем размер массива создается. [ Поскольку предполагается, что функции распределения возвращают указатели на хранилище, которое соответствующим образом выровнено для объектов любого типа с фундаментальным выравниванием, это ограничение накладных расходов на выделение массива допускает общую идиому выделения массивов символов, в которые позже будут помещены объекты других типов. ]Note: end note

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

new-placementСинтаксис используется для предоставления дополнительных аргументов в функцию распределения; такое выражение называется a placement new-expression.

Разрешение перегрузки выполняется при вызове функции, созданной путем сборки списка аргументов. Первый аргумент - это объем запрошенного пространства и имеет тип std​::​size_­t. Если тип выделенного объекта имеет выравнивание по новому-расширенному, следующий аргумент - это выравнивание типа и имеет тип std​::​align_­val_­t. Если используется new-placementсинтаксис, initializer-clauses в нем expression-list находятся следующие аргументы. Если совпадающая функция не найдена и у выделенного типа объекта есть выравнивание "новое-расширенное", аргумент выравнивания удаляется из списка аргументов, и снова выполняется разрешение перегрузки.

[Example:

  • new T приводит к одному из следующих вызовов:

    operator new(sizeof(T))
    operator new(sizeof(T), std::align_val_t(alignof(T)))
  • new(2,f) T приводит к одному из следующих вызовов:

    operator new(sizeof(T), 2, f)
    operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
  • new T[5] приводит к одному из следующих вызовов:

    operator new[](sizeof(T) * 5 + x)
    operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)))
  • new(2,f) T[5] приводит к одному из следующих вызовов:

    operator new[](sizeof(T) * 5 + x, 2, f)
    operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)), 2, f)

Здесь каждый экземпляр x - неотрицательное неопределенное значение, представляющее накладные расходы на выделение массива; результат new-expressionбудет компенсирован на эту сумму от значения, возвращаемого operator new[]. Эти накладные расходы могут применяться ко всем массивам new-expressions, включая те, которые относятся к библиотечной функции operator new[](std​::​size_­t, void*) и другим функциям размещения. Сумма накладных расходов может варьироваться от одного вызова new к другому. ]end example

[ Note: Если функция распределения не имеет не-выброса exception specification, это указывает на сбой выделения памяти путем выдачи исключения ( , пункт , ); в противном случае он возвращает ненулевой указатель. Если функция выделения имеет спецификацию исключения, не вызывающего выброса, она возвращает значение null, чтобы указать на сбой выделения памяти, и ненулевой указатель в противном случае. ] Если функция распределения - это form ( ) без выделения памяти, которая возвращает значение null, поведение не определено. В противном случае, если функция распределения возвращает ноль, инициализация не должна выполняться, функция освобождения не должна вызываться, а значение должно быть нулевым.std​::​bad_­alloc [basic.stc.dynamic.allocation] [except] [bad.alloc]end note[new.delete.placement]new-expression

[ Note: Когда функция распределения возвращает значение, отличное от нуля, это должен быть указатель на блок памяти, в котором было зарезервировано пространство для объекта. Предполагается, что блок памяти правильно выровнен и имеет запрошенный размер. Адрес созданного объекта не обязательно будет таким же, как у блока, если объект является массивом. ]end note

A, new-expressionкоторый создает объект типа, T инициализирует этот объект следующим образом:

  • Если new-initializerопущен, объект инициализируется по умолчанию ([dcl.init]). [ Note: Если инициализация не выполняется, объект имеет неопределенное значение. ] end note

  • В противном случае new-initializerинтерпретируется в соответствии с правилами инициализации [dcl.init] для прямой инициализации.

Вызов функции распределения выполняется до вычислений выражений в new-initializer. Инициализация выделенного объекта выполняется перед вычислением значения new-expression.

Если new-expressionсоздает объект или массив объектов типа класса, контроль доступа и неоднозначности выполняется для функции распределения, deallocation functionа также constructor. Если new-expression создает массив объектов типа класса, destructor потенциально вызывается.

Если какая-либо часть описанной выше инициализации объекта80 завершается выдачей исключения и может быть найдена подходящая функция освобождения, вызывается функция освобождения, чтобы освободить память, в которой создавался объект, после чего исключение продолжает распространяться в контексте. из new-expression. Если не удается найти однозначно совпадающую функцию освобождения памяти, распространение исключения не приводит к освобождению памяти объекта. [ Note: Это уместно, когда вызываемая функция распределения не выделяет память; в противном случае это может привести к утечке памяти. ]end note

Если new-expressionначинается с унарного ​::​ оператора, имя функции освобождения ищется в глобальной области видимости. В противном случае, если выделенный тип является типом класса T или его массивом, имя функции освобождения ищется в области видимости T. Если этот поиск не может найти имя или если выделенный тип не является типом класса или его массивом, имя функции освобождения ищется в глобальной области.

Объявление функции освобождения размещения соответствует объявлению функции распределения размещения, если она имеет такое же количество параметров и после преобразования параметров ([dcl.fct]) все типы параметров, кроме первого, идентичны. Если поиск находит единственную подходящую функцию освобождения, будет вызвана эта функция; в противном случае функция освобождения памяти не будет вызвана. Если поиск находит a usual deallocation function с параметром типа std​::​size_­t и эта функция, рассматриваемая как функция освобождения размещения, была бы выбрана в качестве соответствия для функции распределения, программа имеет неправильный формат. Для функции распределения, не связанной с размещением, обычный поиск функции освобождения используется для поиска соответствующей функции освобождения ([expr.delete]) [Example:

struct S {
  // Placement allocation function:
  static void* operator new(std::size_t, std::size_t);

  // Usual (non-placement) deallocation function:
  static void operator delete(void*, std::size_t);
};

S* p = new (0) S;   // ill-formed: non-placement deallocation function matches
                    // placement allocation function

end example]

Если a new-expressionвызывает функцию освобождения, она передает значение, возвращенное при вызове функции распределения, в качестве первого аргумента типа void*. Если вызывается функция освобождения размещения, ей передаются те же дополнительные аргументы, которые были переданы функции распределения размещения, то есть те же аргументы, что и те, которые указаны в new-placementсинтаксисе. Если реализации разрешено делать копию любого аргумента как часть вызова функции распределения, разрешается делать копию (того же исходного значения) как часть вызова функции освобождения или повторно использовать копию сделано как часть вызова функции распределения. Если копия пропущена в одном месте, нет необходимости опускать ее в другом.

Если функция преобразования возвращает целочисленный тип со знаком, второе стандартное преобразование преобразуется в тип без знака std​::​size_­t и, таким образом, предотвращает любую попытку впоследствии обнаружить отрицательное значение.

Это может включать оценку new-initializerи / или вызов конструктора.

8.3.5 Delete [expr.delete]

delete-expressionОператор разрушает most derived object или массив , созданный new-expression.

delete-expression:
	::opt delete cast-expression
	::opt delete [ ] cast-expression

Первый вариант предназначен для объектов, не являющихся массивами, а второй - для массивов. Всякий раз, когда за delete ключевым словом сразу следуют пустые квадратные скобки, оно должно интерпретироваться как вторая альтернатива.81 Операнд должен иметь указатель на тип объекта или тип класса. Если тип класса, операнд contextually implicitly converted указывает на тип объекта.82 В delete-expressionрезультате «S имеет тип void.

Если операнд имеет тип класса, операнд преобразуется в тип указателя путем вызова вышеупомянутой функции преобразования, и преобразованный операнд используется вместо исходного операнда в оставшейся части этого раздела. В первой альтернативе (delete object) значением операнда delete может быть значение нулевого указателя, указатель на объект, не являющийся массивом, созданный предыдущим new-expression, или указатель на, subobject представляющий base class такой объект. В противном случае поведение не определено. Во второй альтернативе (delete array) значение операнда delete может быть значением нулевого указателя или значением указателя, полученным в результате предыдущего массива new-expression.83 В противном случае поведение не определено. [ Note: Это означает, что синтаксис delete-expressionдолжен соответствовать типу выделенного объекта new, а не синтаксису new-expression. ] [ Указатель на тип может быть операндом a ; в выражении указателя нет необходимости перед его использованием в качестве операнда . ]end noteNote: const delete-expressioncast away the constnessdelete-expressionend note

В первой альтернативе (delete object), если статический тип удаляемого объекта отличается от его динамического типа, статический тип должен быть базовым классом динамического типа удаляемого объекта, а статический тип должен иметь виртуальный тип. деструктор или поведение не определено. Во второй альтернативе (delete array), если динамический тип удаляемого объекта отличается от его статического типа, поведение не определено.

cast-expressionВ delete-expressionдолжна быть оценена только один раз.

Если удаляемый объект имеет неполный тип класса на момент удаления, а полный класс имеет нетривиальный деструктор или функцию освобождения, поведение не определено.

Если значение операнда delete-expressionне является значением нулевого указателя, delete-expressionон вызовет деструктор (если есть) для объекта или элементов удаляемого массива. В случае с массивом элементы будут уничтожены в порядке убывания адреса (то есть в порядке, обратном завершению их конструктора; см. [class.base.init]).

Если значение операнда delete-expressionне является значением нулевого указателя, то:

  • Если вызов выделения для new-expressionудаляемого объекта не был пропущен и выделение не было расширено ([expr.new]), delete-expressionобъект должен вызвать a deallocation function. Значение, возвращаемое из вызова распределения, new-expressionдолжно быть передано в качестве первого аргумента функции освобождения.

  • В противном случае, если выделение было расширено или было предоставлено путем расширения выделения другого new-expression, и delete-expressionдля каждого другого значения указателя, созданного a, new-expressionкоторый имел хранилище, предоставленное расширенным new-expression, было оценено, то delete-expressionдолжен вызвать функцию освобождения. Значение, возвращаемое из вызова распределения расширенного, new-expression должно быть передано в качестве первого аргумента функции освобождения.

  • В противном случае delete-expressionфункция освобождения памяти не будет вызвана.

[ Note: Функция освобождения вызывается независимо от того, генерирует ли деструктор для объекта или какого-либо элемента массива исключение. ] Если значение операнда является значением нулевого указателя, не указано, будет ли вызываться функция освобождения, как описано выше.end notedelete-expression

[ Note: Реализация предоставляет определения по умолчанию operator delete для функций глобального освобождения для не-массивов ([new.delete.single]) и operator delete[] для массивов ([new.delete.array]). Программа на C ++ может предоставлять альтернативные определения этих функций ([replacement.functions]) и / или версии для конкретных классов ([class.free]). ]end note

Когда ключевому слову delete в a delete-expressionпредшествует унарный ​::​ оператор, имя функции освобождения ищется в глобальной области. В противном случае поиск учитывает функции освобождения, специфичные для класса ([class.free]). Если не найдена зависящая от класса функция освобождения, имя функции освобождения ищется в глобальной области видимости.

Если поиск функции освобождения обнаруживает более одной обычной функции освобождения, вызываемая функция выбирается следующим образом:

  • Если тип имеет выравнивание "новый-расширенный", std​::​align_­val_­t предпочтительнее использовать функцию с параметром типа ; в противном случае предпочтительнее использовать функцию без такого параметра. Если найдена ровно одна предпочтительная функция, выбирается эта функция, и процесс выбора завершается. Если найдено более одной предпочтительной функции, все нежелательные функции исключаются из дальнейшего рассмотрения.

  • Если функции освобождения имеют область видимости класса, std​::​size_­t выбирается функция без параметра типа .

  • Если тип является полным и если только для второй альтернативы (удалить массив), операнд является указателем на тип класса с нетривиальным деструктором или его (возможно, многомерным) массивом, функция с параметром тип std​::​size_­t выбран.

  • В противном случае не указано, std​::​size_­t выбрана ли функция освобождения с параметром типа .

Когда delete-expression выполняется a , выбранная функция освобождения должна вызываться с адресом наиболее производного объекта в delete object случае или адресом объекта, соответствующим образом скорректированным с учетом накладных расходов на выделение массива ([expr.new]) в delete array случае, в качестве ее первого аргумента. Если используется функция освобождения с параметром типа std​::​align_­val_­t , выравнивание типа удаляемого объекта передается как соответствующий аргумент. Если используется функция освобождения с параметром типа std​::​size_­t , размер наиболее производного типа или массива плюс накладные расходы на выделение соответственно передается в качестве соответствующего аргумента.84 [ Note: Если это приводит к вызову обычной функции освобождения памяти, и либо первый аргумент не был результатом предыдущего вызова обычной функции распределения, либо второй аргумент не был соответствующим аргументом в указанном вызове, поведение не определено ([new.delete.single], [new.delete.array]). ]end note

Контроль доступа и неоднозначности выполняется как для функции освобождения, так и для деструктора ([class.dtor], [class.free]).

Лямбда-выражение lambda-introducer, состоящее из пустых квадратных скобок, может следовать за delete ключевым словом, если лямбда-выражение заключено в круглые скобки.

Это означает, что объект нельзя удалить с помощью указателя типа, void* поскольку void он не является типом объекта.

Для массивов ненулевой длины это то же самое, что указатель на первый элемент массива, созданного им new-expression. Массивы нулевой длины не имеют первого элемента.

Если статический тип удаляемого объекта полный и отличается от динамического типа, а деструктор не виртуальный, размер может быть неправильным, но этот случай уже не определен, как указано выше.

8.3.6 Alignof [expr.alignof]

alignof Выражение дает требование выравнивания его типа операнда. Операнд должен type-id представлять собой полный тип объекта или его массив, или ссылку на один из этих типов.

Результат - интегральная константа типа std​::​size_­t.

Когда alignof применяется к ссылочному типу, результатом является выравнивание ссылочного типа. Когда alignof применяется к типу массива, результатом является выравнивание типа элемента.

8.3.7 noexcept operator [expr.unary.noexcept]

noexcept Оператор определяет , является ли оценка ее операнда, который является unevaluated operand, может throw an exception.

noexcept-expression:
	noexcept ( expression )

Результатом noexcept оператора является константа типа bool и prvalue.

Результатом noexcept оператора является, true если только он не expressionявляется potentially-throwing.