к самой функции.
Результатом операции будет константа типа size_t. Этот тип
определен в стандартном заголовочном файле <stddef.h> и является
зависящим от реализации беззнаковым целочисленным типом.
Операция new предназначена для создания объекта типа имя-типа
($$R.8.1). Этот тип должен быть типом объекта и функции нельзя
размещать с ее помощью, хотя указатели на функции можно.
выражение-размещения:
::opt new параметры-new opt имя-типа-new инициализатор-new
::opt new параметры-new opt ( имя-типа ) инициализатор-new
параметры-new:
( список-выражений )
имя-типа-new:
список-спецификаций-типа описатель-new opt
описатель-new:
* список-спецификаций-cv opt описатель-new opt
имя-класса :: список-спецификаций-cv opt описатель-new opt
описатель-new opt [ выражение ]
инициализатор-new:
( список-инициализаторов opt )
Время жизни объекта, созданного с помощью new, не ограничивается
областью видимости, в которой он был создан. Операция new возвращает
указатель на созданный объект. Если объект является массивом,
возвращается указатель на начальный элемент массива. Например,
обе операции new int и new int[1] возвратят int* , а типом
new int[i][10] будет int(*)[10]. Если описывается тип массива
($$R.8.2.4), все размерности, кроме первой, должны быть выражениями-
константами ($$R.5.19) с положительным значением. Первая размерность
массива может задаваться произвольным выражением, даже если
используется имя-типа (здесь нарушается общее требование, чтобы
размерности массива в конструкции имя-типа были
выражениями-константами ($$R.5.19)).
Допускается, чтобы вызывалась функция operator new() с параметром
нуль. В таком случае возвращается указатель на объект. При повторении
таких вызовов будут возвращаться указатели на разные объекты.
Конструкция список-спецификаций-типа не должна содержать const,
volatile, описание класса или перечисления.
Для резервирования памяти операция new обращается к функции
operator new() ($$R.12.5). При размещении объекта типа T ей в
качестве первого параметра передается sizeof(T). Конструкция
параметры-new используется для передачи дополнительных параметров.
Например, операция new T приводит к вызову operator new(sizeof(T)),
а операция new(2,f) T приводит к вызову operator new(sizeof(T),2,f).
Конструкция параметры-new может использоваться только, если
описана функция operator new() с параметрами соответствующих типов.
Если с помощью операции new создается объект не типа класс
(в том числе и массив объектов типа класс), то вызывается глобальная
функция ::operator new(). Если с помощью new создается объект класса
T, вызывается функция T::operator new(), если она существует
(используя обычные правила просмотра при поиске членов класса и его
базовых классов, $$R.10.1.1), иначе вызывается глобальная функция
::operator new(). Использование операции ::new() гарантирует, что
будет вызываться глобальная функция ::operator new(), даже если
существует T::operator new().
Конструкция выражение-размещения может содержать инициализатор-new.
Для объектов классов с конструкторами ($$R.12.1) задаваемый ею
список параметров будет использоваться при вызове конструктора, в
других случаях конструкция инициализатор-new должна иметь вид
( выражение ) или ( ). Если выражение присутствует, оно используется
для инициализации объекта, если его нет, объект начнет существование
с неопределенным значением.\
Если класс имеет конструктор, объект этого класса можно создать
с помощью new только при условии, что заданы подходящие параметры,
или, что класс имеет стандартный конструктор ($$R.12.1).
Отводит ли память при создании объекта типа класс сама функция
operator new, или оставляет это на конструктор, зависит от реализации.
Как для конструктора, так и для функции operator new() проводится
проверка возможности доступа и однозначности ($$R.12).
Для массивов нельзя задавать инициализаторы. Массивы объектов
типа класса с конструктором можно создавать с помощью операции new
только, если конструктор класса является стандартным ($$R.12.1).
В этом случае стандартный конструктор будет вызываться для каждого
элемента массива.
Инициализация производится только в том случае, когда функция
operator new() возвращает ненуль. Если она возвращает 0 (пустой
указатель), значение выражения есть 0.
Порядок вычисления выражения вызова operator new() для получения
памяти и порядок вычисления параметров конструктора неопределен.
Так же неопределено вычисляются ли параметры конструктора, если
функция operator new() возвратила 0.
В конструкции имя-типа-new скобки использовать необязательно.
Тогда обращение
new int (*[10])(); // error
может привести к ошибке, т.к. операции применяются в таком порядке
(new int) (*[10])(); // error
Объекты сложного типа можно задать в операции new с помощью явно
указанных скобок, например, обращение
new (int (*[10])());
размещает массив из 10 указателей на функции (не имеющие параметров
и возвращающие int).
Конструкции имя-типа-new в выражение-размещения должна быть
самой длинной из возможных последовательностей конструкций
описатель-new. Это предотвращает коллизии между операциями из
описателей &, *, [] и их двойниками из выражения, например,
new int* i; // syntax error: parsed as `(new int*) i'
// not s `(new int)*i'
Символ * используется в описателе указателя, а не в качестве
операции умножения.
Операция delete уничтожает объект, созданный с помощью new.
выражение-освобождения:
::opt delete выражение-приведения
::opt delete [] выражение-приведения
Результат имеет тип void. Операндом delete должен быть указатель,
который возвращает new. Эффект применения операции delete к указателю,
который не получен в результате операции new без задания
параметры-new, считается неопределенным и обычно приводит к опасным
последствиям. Однако гарантируется, что удаление по указателю с
нулевым значением безопасно.
Результат попытки доступа к удаленному объекту неопределен, а
удаление объекта может изменить его значение. Более того, если
выражение, задающее объект, является изменяемым адресом, его
значение после удаления неопределено.
Нельзя удалять указатель на константу.
Операция delete вызывает деструктор (если он есть $$12.4)
для объекта, на который настроен ее операнд.
Для освобождения памяти, отведенной под указываемый объект,
операция delete вызывает функцию operator delete ($$R.12.5).
Для объектов, не имеющих тип класс (в том числе и для массивов
классов), используется глобальная функция ::operator delete().
Для объекта типа класс T вызывается функция T::operator delete(),
если она есть (используя обычные правила просмотра при поиске
членов класса и производных от него классов, $$R.10.1.1), в
противном случае вызывается глобальная функция ::operator delete().
Обращение ::delete гарантирует, что будет вызываться глобальная
функция ::operator delete(), даже если существует T::operator delete().
Для удаления массивов используется обращение вида
delete [ ] выражение-приведения
Здесь выражение должно указывать на массив. Если есть деструкторы,
они будут вызываться для удаления указанных объектов.
Результат удаления массива с помощью простого обращения delete
неопределен, так же как и удаление одиночного объекта с помощью
delete [].
Явное преобразование типа можно задать с помощью функциональной
записи ($$R.5.2.3) или с помощью операции приведения.
выражение-приведения:
унарное-выражение
( имя-типа ) выражение-приведения
Задание с помощью операции приведения используется для обозначения
преобразования к типу, который не является конструкцией
имя-простого-типа.
В операции приведения нельзя определять типы.
Всякое преобразование типа, не упомянутое здесь и не являющееся
преобразованием явно определенным пользователем ($$R.12.3), считается
ошибкой.
Любой тип, который можно преобразовать в другой с помощью
стандартного преобразования ($$R.4), можно также преобразовать
с помощью явного преобразования (приведения) и смысл преобразования
будет тот же.
Указатель можно преобразовать к любому целочисленному типу,
достаточно большому, чтобы вместить значение указателя. Алгоритм
преобразования зависит от реализации, но предполагается, что он
будет естественным для того, кто знает систему адресации, используемой
машины.
Значение целочисленного типа может быть явно преобразовано в
указатель. Указатель, преобразованный в целое достаточного размера
(если такие есть в реализации), и преобразованный обратно к типу
указателя, должен иметь свое первоначальное значение. Все другие
детали перевода указателя в целое и обратно зависят от реализации.
Указатель на объект одного типа может быть преобразован в
указатель на объект другого типа (с соблюдением ограничений, указанных
здесь). Использование получившегося указателя может вызвать
особую адресную ситуацию ("неверный адрес"), если преобразуемый
указатель не
настроен на объект, правильным образом выравненный в памяти.
Гарантируется, что указатель на объект данного размера можно
преобразовать в указатель на объект равного или меньшего размера
и провести обратное преобразование без изменения значения указателя.
На различных машинах двоичное представление указателей может быть
различно как и требования на выравнивания объектов. Составные
объекты выравниваются по самой строгой границе, требуемой их
составляющими. Указатель типа void* считается совместимым с
указателем на объект любого типа.
Указатель на класс B можно преобразовать в указатель на класс D,
для которого класс B является прямо или опосредованно базовым
классом, если существует однозначное преобразование из D в B
($$R.4.6, $$.R10.1.1) и если B является виртуальным базовым классом
($$R.10.1). Такое приведение от базового класса к производному
классу предполагает, что объект базового класса является вложенным
по отношению к объекту производного класса. В результате получится
указатель, настроенный на объемлющий объект производного класса.
Если объект базового класса не содержится ни в каком объекте
производного класса, такая операция приведения может вызвать
особую ситуацию.
Пустой указатель (0) преобразуется сам в себя.
Пока еще неопределенный класс можно использовать в операции
приведения указателя, в этом случае никаких допущений о структуре
класса не делается ($$R.10.1).
Любой объект можно явно преобразовать к типу ссылки X&, если
указатель на этот объект можно явно преобразовать в тип X*.
В результате приведения к ссылке не происходит вызовов конструкторов
или функций преобразований. Преобразование ссылки на базовый класс
в ссылку на производный класс рассматривается аналогично
преобразованию указателя на базовый класс в указатель на
производный класс, учитывая вопросы однозначности, виртуальных
классов и т.д.
Результатом приведения к ссылке является адрес, в отличие от всех
остальных приведений. Результат приведения указателя или ссылки
настроен на тот же объект, что и исходное выражение без операции
приведения.
Указатель на функцию можно явно преобразовать в указатель на
некоторый объект при условии, что тип указателя на этот объект
достаточно велик, чтобы хранить указатель на функцию. Указатель
на некоторый объект можно явно преобразовать в указатель на функцию
при условии, что тип указателя на функцию достаточно велик, чтобы
хранить указатель на этот объект. В обоих случаях, использование
указателя, получившегося в результате преобразования, может
вызвать особую адресную ситуацию, или что-нибудь похуже,
если исходный указатель не настроен на соответствующий объект.
Указатель на функцию одного типа можно явно преобразовать в
указатель на функцию другого типа. Результат вызова функции с
помощью указателя на функцию, тип которой отличен от типа,
использованного при определении первой функции, неопределен
(см. так же $$R.4.6).
Объект или значение можно преобразовать в объект типа класс
только при условии, что определен подходящий конструктор или
операция преобразования ($$R.12.3).
Указатель на член можно явно преобразовать в указатель на другой
член, если оба участвующих типа являются типами указателей
на члены одного класса, или, если оба типа являются указателями
на функцию-член классов, один из которых получается как однозначное
производное от другого ($$R.4.8).
Указатель на объект с типом, имеющим спецификацию const, можно
привести к указателю с типом без спецификации const. Получившийся
в результате указатель будет настроен на исходный объект.
Объект с типом, имеющим спецификацию const, или ссылку на объект
такого типа можно привести в ссылку на объект с типом без const.
Получившаяся в результате ссылка будет настроена на исходный
объект. В результате попытки изменить этот объект с помощью
такой ссылки или указателя может возникнуть особая ситуация или
он будет таким же, как при обращении с помощью исходной ссылки
или указателя к объекту, тип которого не содержит const. Возникнет
ли особая адресная ситуация зависит от реализации.
Указатель на объект типа со спецификацией volatile можно привести
к указателю на объект типа без volatile. В результате получится
указатель, настроенный на исходный объект. Объект типа с volatile
или ссылку на такой объект можно привести к ссылке на объект с типом
без volatile.
Операции указатель-на-член применяются слева направо.
выражение-pm:
выражение-приведения
выражение-pm .* выражение-приведения
выражение-pm ->* выражение-приведения
Бинарная операция .* связывает свой второй операнд, который должен
иметь тип "указатель на член класса T", с первым операндом, имеющим
тип класс T или такой класс, для которого T является однозначно
определенным и достижимым базовым классом. Результатом будет объект
или функция с типом, задаваемым вторым операндом.
Бинарная операция ->* связывает свой второй операнд, который должен
иметь тип "указатель на член класса T", с первым операндом, имеющим
тип "указатель на T" или тип "указатель на класс, для которого T
является однозначно определенным и достижимым базовым классом".
Результатом будет объект или функция с типом, задаваемым вторым
операндом.
Если результат .* или ->* есть функция, то его можно использовать
только в качестве операнда операции вызова функции (), например,
операция
(ptr_to_obj->*ptr_to_mfct)(10);
приводит к вызову функции-члена, обозначенной ptr_to_mfct, для
объекта, на который настроен указатель ptr_to_obj. Результат
операции .* или ->* является адресом, если второй операнд есть
адрес.
Мультипликативные операции *, /, и % выполняются слева направо.
Мультипликативное-выражение:
выражение-pm
мультипликативное-выражение * выражение-pm
мультипликативное-выражение / выражение-pm
мультипликативное-выражение % выражение-pm
Операнды операций * и / должны иметь арифметический тип, операнды
для % должны быть целочисленного типа. Обычные арифметические
преобразования ($$R.4.5) производятся над операндами и определяют
тип результата.
Бинарная операция * обозначает умножение.
Бинарная операция / вычисляет частное, а бинарная операция %
вычисляет остаток от деления первого выражения на второе. Если
второй операнд у / или % есть 0, результат неопределен, иначе
(a/b)*b + a%b должно равняться a. Если оба операнда неотрицательны,
то таким же будет и результат, в противном случае знак результата
определяется реализацией.
R.5.7 Аддитивные операции
Аддитивные операции + и - выполняются слева направо, при этом
происходят обычные арифметические преобразования ($$R.4.5)
операндов арифметического типа.
аддитивное-выражение:
мультипликативное-выражение
аддитивное выражение + мультипликативное-выражение
аддитивное-выражение - мультипликативное-выражение
Операнды должны быть арифметического типа или типа указателя.
Результатом операции + является сумма операндов. Можно складывать
указатель на объект в массиве и значение любого целочисленного типа.
Результатом будет указатель того же типа, что и исходный указатель,
но он будет настроен на другой объект массива
с заданным смещением от исходного объекта. Так, если P
есть указатель на объект массива, выражение P+1 является указателем
на следующий объект массива. Если же получившийся в результате
сложения указатель вышел за границы массива, результат будет
неопределенным, кроме случая, когда указатель настроен на первый адрес
больший верхней границы массива.
Результатом операции - будет разность операндов. Значение
любого целочисленного типа можно вычитать из указателя, при этом
применяются те же преобразования, что и для операции +.
Никакие другие сочетания типов для указателей не допустимы.
Если вычитаются два указателя на объекты одного типа, результатом
будет целочисленное значение со знаком, которое показывает на сколько
объектов этого типа отстоят друг от друга указуемые объекты. Указатели
на соседние элементы массива отстоят на 1. Тип результата зависит от
реализации, но он должен быть определен как ptrdiff_t в стандартном
заголовочном файле <stddef.h>. Результат не определен, если указатели
не настроены на элементы одного массива. Если P есть указатель
на последний элемент массива, то (P+1) - 1 есть P.
Операции сдвигов << и >> выполняются слева направо.
сдвиговое-выражение:
аддитивное-выражение
сдвиговое-выражение << аддитивное выражение
сдвиговое-выражение >> аддитивное выражение
Операнды должны быть целочисленного типа, и над ними производятся
стандартные целочисленные преобразования. Тип результата совпадает
с типом преобразованного левого операнда. Результат не определен,
если правый операнд отрицателен или больше или равен числу разрядов
в двоичном представлении преобразованного левого операнда.
Значением выражения E1<<E2 будет E1 (рассматриваемое как набор
разрядов), сдвинутое влево на E2 разрядов, причем освободившиеся
разряды заполняются нулями. Значением выражения E1>>E2 будет E1,
сдвинутое вправо на E2 разрядов. Если E1 беззнакового типа или
имеет неотрицательное значение, гарантируется, что сдвиг вправо
- логический (заполнение нулями), иначе результат зависит от реализации.
Операции отношения выполняются слева направо, но этот факт мало что
дает, ибо выражение a<b<c означает (a<b)<c, а вовсе не (a<b)&&(b<c).
выражение-отношения:
сдвиговое-выражение
выражение-отношения < сдвиговое-выражение
выражение-отношения > сдвиговое-выражение
выражение-отношения <= сдвиговое-выражение
выражение-отношения >= сдвиговое-выражение
Операнды должны быть арифметического типа или типа указателей.
Операции < (меньше чем), > (больше чем), <= (меньше или равно) и
>= (больше или равно) дают результат 0, если указанное отношение
не выполняется, и 1, если оно выполняется. Тип результата int.
Над арифметическими операндами выполняются обычные арифметические
преобразования. Над указателями выполняются обычные преобразования
указателей. Предполагается, что любой указатель можно сравнить
с выражением, имеющим результат 0, и любой указатель можно сравнить
с указателем, имеющим тип void* (в этом случае указатель сначала
преобразуется к типу void*). Указатели на объекты или функции
одного типа (после преобразования указателей) можно сравнивать,
результат зависит от взаимного расположения в памяти объектов или
функций.
Два указателя на один и тот же объект считаются равными. Если
два указателя настроены на нестатические члены одного объекта, то
указатель, настроенный на член, описанный позднее, считается
большим, при условии, что члены не имеют разных спецификаций
указатель-доступа ($$R.11.1), а класс не является объединением.
Если два указателя настроены на нестатические члены одного объекта
и спецификации указателей-доступа ($$R.11.1) этих членов различны,
результат будет не определен. Если два указателя настроены на члены
(данные) одного и того же объединения, они считаются равными. Если два
указателя настроены на элементы одного массива или смотрят за границу
массива, то указатель, настроенный на элемент с большим индексом,
будет большим. Все другие сравнения указателей определяются
реализацией.
выражение-равенства:
выражение-отношения
выражение-равенства == выражение-отношения
выражение-равенства != выражение-отношения
Операции == (равно) и != (не равно) аналогичны операциям
отношения, за исключением того, что их приоритет ниже. (Таким образом,
операция a<b == c<d дает результат 1, если выражения a<b и c<d
имеют одно и то же значение.)
Кроме этого, можно сравнивать указатели на члены одного типа.
Производятся преобразования указателя на член ($$R.4.8). Указатель
на член можно сравнить с выражением-константой, которое дает
результат 0.
выражение-И:
выражение-равенства
выражение-И & выражение-равенства
Выполняются обычные арифметические преобразования, результат -
поразрядная функция И от операндов. Операция применима только к
целочисленным операндам.
выражение-исключающего-ИЛИ:
выражение-И
выражение-исключающего-ИЛИ ^ выражение-И
Выполняются обычные арифметические преобразования, результат -
поразрядная исключающая функция ИЛИ от операндов. Операция применима
только к целочисленным операндам.
выражение-ИЛИ:
выражение-исключающего-ИЛИ
выражение-ИЛИ | выражение-исключающего-ИЛИ
Выполняются обычные арифметические преобразования, результат -
поразрядная функция ИЛИ от операндов. Операция применима только
к целочисленным типам.
логическое-выражение-И:
выражение-ИЛИ
логическое-выражение-И && выражение-ИЛИ
Операции && выполняются слева направо. Такая операция дает результат
1, если оба операнда ее отличны от нуля, иначе результат - 0. В
отличие от & при операции && гарантируется вычисление слева направо,
более того, второй операнд не вычисляется, если первый операнд равен 0.
Операнды не обязательно имеют одинаковый тип, но каждый должен быть
арифметического типа или типа указателя. Тип результата int. Все
побочные эффекты вычисления первого выражения могут возникать до
вычисления второго выражения.
логическое-выражение-ИЛИ:
логическое-выражение-И
логическое-выражение-ИЛИ || логическое-выражение-И
Операции || выполняются слева направо. Результат операции 1, если
один из ее операндов отличен от нуля, иначе результат - 0. В отличие
от | при операции || гарантируется вычисление слева направо, более
того, второй операнд не вычисляется, если значение первого операнда
отлично от нуля.
Операнды не обязательно имеют одинаковый тип, но каждый должен быть
арифметического типа или типа указателя. Тип результата int. Все
побочные эффекты вычисления первого выражения могут возникать до
вычисления второго выражения.
выражение-условия:
логическое-выражение-ИЛИ
логическое-выражение-ИЛИ ? выражение : выражение-условия
Условные выражения выполняются слева направо. Первое выражение должно
быть арифметического типа или типа указателя. Оно вычисляется, и,
если результат его отличен от нуля, то результатом условного выражения
будет значение второго выражения, иначе результат - значение третьего
выражения. Все побочные эффекты вычисления первого выражения могут
возникать до вычисления второго или третьего выражения.
Если второе и третье выражение арифметического типа, и типы их
совпадают, то таким же будет и тип результата, если они различаются, то
выполняются обычные арифметические преобразования, чтобы привести их
к общему типу. Если второе и третье выражение являются
указателями или выражением-константой, дающим результат 0, выполняются
преобразования указателей, чтобы привести результаты выражений к
общему типу. Если второе и третье выражение являются ссылками,
выполняется преобразование ссылок, чтобы привести их к общему типу.
Если второе и третье выражение имеют тип void, общий тип
будет void. Если второе и третье выражение имеют один тип
класс T, общим типом будет T. Иначе, выражение считается недопустимым.
Тип результата есть общий тип. Вычисляется только второе или третье
выражение (но не оба). Результат будет адресом, если второй и
третий операнд одного типа и являются адресами.
Существует несколько операций присваивания, все они выполняются
справа налево. Для всех них требуется, чтобы левым операндом был
изменяемый адрес. Тип выражения присваивания совпадает с типом
левого операнда. Результат операции присваивание - значение,
хранящееся в левом операнде после того как произошло присваивание.
Результат является адресом.
выражение-присваивания:
выражение-условия
унарное-выражение операция-присваивания выражение-присваивания
операция-присваивания: один из
= *= /= %= += -= >>= <<= &= ^= |=
При простом присваивании (=) значение выражения заменяет собой значение
объекта, с которым сопоставляется левый операнд. Если оба операнда
арифметического типа, правый операнд, прежде чем произойдет
присваивание, преобразуется к типу левого операнда. Неявные
преобразования к типу перечисления ($$R.7.2) не производятся, поэтому
если левый операнд имеет тип перечисления, правый операнд должен
быть таким же. Если левый операнд имеет тип указателя, правый
операнд должен быть типа указателя или выражением-константой, дающим
Результатом операции будет константа типа size_t. Этот тип
определен в стандартном заголовочном файле <stddef.h> и является
зависящим от реализации беззнаковым целочисленным типом.
Операция new предназначена для создания объекта типа имя-типа
($$R.8.1). Этот тип должен быть типом объекта и функции нельзя
размещать с ее помощью, хотя указатели на функции можно.
выражение-размещения:
::opt new параметры-new opt имя-типа-new инициализатор-new
::opt new параметры-new opt ( имя-типа ) инициализатор-new
параметры-new:
( список-выражений )
имя-типа-new:
список-спецификаций-типа описатель-new opt
описатель-new:
* список-спецификаций-cv opt описатель-new opt
имя-класса :: список-спецификаций-cv opt описатель-new opt
описатель-new opt [ выражение ]
инициализатор-new:
( список-инициализаторов opt )
Время жизни объекта, созданного с помощью new, не ограничивается
областью видимости, в которой он был создан. Операция new возвращает
указатель на созданный объект. Если объект является массивом,
возвращается указатель на начальный элемент массива. Например,
обе операции new int и new int[1] возвратят int* , а типом
new int[i][10] будет int(*)[10]. Если описывается тип массива
($$R.8.2.4), все размерности, кроме первой, должны быть выражениями-
константами ($$R.5.19) с положительным значением. Первая размерность
массива может задаваться произвольным выражением, даже если
используется имя-типа (здесь нарушается общее требование, чтобы
размерности массива в конструкции имя-типа были
выражениями-константами ($$R.5.19)).
Допускается, чтобы вызывалась функция operator new() с параметром
нуль. В таком случае возвращается указатель на объект. При повторении
таких вызовов будут возвращаться указатели на разные объекты.
Конструкция список-спецификаций-типа не должна содержать const,
volatile, описание класса или перечисления.
Для резервирования памяти операция new обращается к функции
operator new() ($$R.12.5). При размещении объекта типа T ей в
качестве первого параметра передается sizeof(T). Конструкция
параметры-new используется для передачи дополнительных параметров.
Например, операция new T приводит к вызову operator new(sizeof(T)),
а операция new(2,f) T приводит к вызову operator new(sizeof(T),2,f).
Конструкция параметры-new может использоваться только, если
описана функция operator new() с параметрами соответствующих типов.
Если с помощью операции new создается объект не типа класс
(в том числе и массив объектов типа класс), то вызывается глобальная
функция ::operator new(). Если с помощью new создается объект класса
T, вызывается функция T::operator new(), если она существует
(используя обычные правила просмотра при поиске членов класса и его
базовых классов, $$R.10.1.1), иначе вызывается глобальная функция
::operator new(). Использование операции ::new() гарантирует, что
будет вызываться глобальная функция ::operator new(), даже если
существует T::operator new().
Конструкция выражение-размещения может содержать инициализатор-new.
Для объектов классов с конструкторами ($$R.12.1) задаваемый ею
список параметров будет использоваться при вызове конструктора, в
других случаях конструкция инициализатор-new должна иметь вид
( выражение ) или ( ). Если выражение присутствует, оно используется
для инициализации объекта, если его нет, объект начнет существование
с неопределенным значением.\
Если класс имеет конструктор, объект этого класса можно создать
с помощью new только при условии, что заданы подходящие параметры,
или, что класс имеет стандартный конструктор ($$R.12.1).
Отводит ли память при создании объекта типа класс сама функция
operator new, или оставляет это на конструктор, зависит от реализации.
Как для конструктора, так и для функции operator new() проводится
проверка возможности доступа и однозначности ($$R.12).
Для массивов нельзя задавать инициализаторы. Массивы объектов
типа класса с конструктором можно создавать с помощью операции new
только, если конструктор класса является стандартным ($$R.12.1).
В этом случае стандартный конструктор будет вызываться для каждого
элемента массива.
Инициализация производится только в том случае, когда функция
operator new() возвращает ненуль. Если она возвращает 0 (пустой
указатель), значение выражения есть 0.
Порядок вычисления выражения вызова operator new() для получения
памяти и порядок вычисления параметров конструктора неопределен.
Так же неопределено вычисляются ли параметры конструктора, если
функция operator new() возвратила 0.
В конструкции имя-типа-new скобки использовать необязательно.
Тогда обращение
new int (*[10])(); // error
может привести к ошибке, т.к. операции применяются в таком порядке
(new int) (*[10])(); // error
Объекты сложного типа можно задать в операции new с помощью явно
указанных скобок, например, обращение
new (int (*[10])());
размещает массив из 10 указателей на функции (не имеющие параметров
и возвращающие int).
Конструкции имя-типа-new в выражение-размещения должна быть
самой длинной из возможных последовательностей конструкций
описатель-new. Это предотвращает коллизии между операциями из
описателей &, *, [] и их двойниками из выражения, например,
new int* i; // syntax error: parsed as `(new int*) i'
// not s `(new int)*i'
Символ * используется в описателе указателя, а не в качестве
операции умножения.
Операция delete уничтожает объект, созданный с помощью new.
выражение-освобождения:
::opt delete выражение-приведения
::opt delete [] выражение-приведения
Результат имеет тип void. Операндом delete должен быть указатель,
который возвращает new. Эффект применения операции delete к указателю,
который не получен в результате операции new без задания
параметры-new, считается неопределенным и обычно приводит к опасным
последствиям. Однако гарантируется, что удаление по указателю с
нулевым значением безопасно.
Результат попытки доступа к удаленному объекту неопределен, а
удаление объекта может изменить его значение. Более того, если
выражение, задающее объект, является изменяемым адресом, его
значение после удаления неопределено.
Нельзя удалять указатель на константу.
Операция delete вызывает деструктор (если он есть $$12.4)
для объекта, на который настроен ее операнд.
Для освобождения памяти, отведенной под указываемый объект,
операция delete вызывает функцию operator delete ($$R.12.5).
Для объектов, не имеющих тип класс (в том числе и для массивов
классов), используется глобальная функция ::operator delete().
Для объекта типа класс T вызывается функция T::operator delete(),
если она есть (используя обычные правила просмотра при поиске
членов класса и производных от него классов, $$R.10.1.1), в
противном случае вызывается глобальная функция ::operator delete().
Обращение ::delete гарантирует, что будет вызываться глобальная
функция ::operator delete(), даже если существует T::operator delete().
Для удаления массивов используется обращение вида
delete [ ] выражение-приведения
Здесь выражение должно указывать на массив. Если есть деструкторы,
они будут вызываться для удаления указанных объектов.
Результат удаления массива с помощью простого обращения delete
неопределен, так же как и удаление одиночного объекта с помощью
delete [].
Явное преобразование типа можно задать с помощью функциональной
записи ($$R.5.2.3) или с помощью операции приведения.
выражение-приведения:
унарное-выражение
( имя-типа ) выражение-приведения
Задание с помощью операции приведения используется для обозначения
преобразования к типу, который не является конструкцией
имя-простого-типа.
В операции приведения нельзя определять типы.
Всякое преобразование типа, не упомянутое здесь и не являющееся
преобразованием явно определенным пользователем ($$R.12.3), считается
ошибкой.
Любой тип, который можно преобразовать в другой с помощью
стандартного преобразования ($$R.4), можно также преобразовать
с помощью явного преобразования (приведения) и смысл преобразования
будет тот же.
Указатель можно преобразовать к любому целочисленному типу,
достаточно большому, чтобы вместить значение указателя. Алгоритм
преобразования зависит от реализации, но предполагается, что он
будет естественным для того, кто знает систему адресации, используемой
машины.
Значение целочисленного типа может быть явно преобразовано в
указатель. Указатель, преобразованный в целое достаточного размера
(если такие есть в реализации), и преобразованный обратно к типу
указателя, должен иметь свое первоначальное значение. Все другие
детали перевода указателя в целое и обратно зависят от реализации.
Указатель на объект одного типа может быть преобразован в
указатель на объект другого типа (с соблюдением ограничений, указанных
здесь). Использование получившегося указателя может вызвать
особую адресную ситуацию ("неверный адрес"), если преобразуемый
указатель не
настроен на объект, правильным образом выравненный в памяти.
Гарантируется, что указатель на объект данного размера можно
преобразовать в указатель на объект равного или меньшего размера
и провести обратное преобразование без изменения значения указателя.
На различных машинах двоичное представление указателей может быть
различно как и требования на выравнивания объектов. Составные
объекты выравниваются по самой строгой границе, требуемой их
составляющими. Указатель типа void* считается совместимым с
указателем на объект любого типа.
Указатель на класс B можно преобразовать в указатель на класс D,
для которого класс B является прямо или опосредованно базовым
классом, если существует однозначное преобразование из D в B
($$R.4.6, $$.R10.1.1) и если B является виртуальным базовым классом
($$R.10.1). Такое приведение от базового класса к производному
классу предполагает, что объект базового класса является вложенным
по отношению к объекту производного класса. В результате получится
указатель, настроенный на объемлющий объект производного класса.
Если объект базового класса не содержится ни в каком объекте
производного класса, такая операция приведения может вызвать
особую ситуацию.
Пустой указатель (0) преобразуется сам в себя.
Пока еще неопределенный класс можно использовать в операции
приведения указателя, в этом случае никаких допущений о структуре
класса не делается ($$R.10.1).
Любой объект можно явно преобразовать к типу ссылки X&, если
указатель на этот объект можно явно преобразовать в тип X*.
В результате приведения к ссылке не происходит вызовов конструкторов
или функций преобразований. Преобразование ссылки на базовый класс
в ссылку на производный класс рассматривается аналогично
преобразованию указателя на базовый класс в указатель на
производный класс, учитывая вопросы однозначности, виртуальных
классов и т.д.
Результатом приведения к ссылке является адрес, в отличие от всех
остальных приведений. Результат приведения указателя или ссылки
настроен на тот же объект, что и исходное выражение без операции
приведения.
Указатель на функцию можно явно преобразовать в указатель на
некоторый объект при условии, что тип указателя на этот объект
достаточно велик, чтобы хранить указатель на функцию. Указатель
на некоторый объект можно явно преобразовать в указатель на функцию
при условии, что тип указателя на функцию достаточно велик, чтобы
хранить указатель на этот объект. В обоих случаях, использование
указателя, получившегося в результате преобразования, может
вызвать особую адресную ситуацию, или что-нибудь похуже,
если исходный указатель не настроен на соответствующий объект.
Указатель на функцию одного типа можно явно преобразовать в
указатель на функцию другого типа. Результат вызова функции с
помощью указателя на функцию, тип которой отличен от типа,
использованного при определении первой функции, неопределен
(см. так же $$R.4.6).
Объект или значение можно преобразовать в объект типа класс
только при условии, что определен подходящий конструктор или
операция преобразования ($$R.12.3).
Указатель на член можно явно преобразовать в указатель на другой
член, если оба участвующих типа являются типами указателей
на члены одного класса, или, если оба типа являются указателями
на функцию-член классов, один из которых получается как однозначное
производное от другого ($$R.4.8).
Указатель на объект с типом, имеющим спецификацию const, можно
привести к указателю с типом без спецификации const. Получившийся
в результате указатель будет настроен на исходный объект.
Объект с типом, имеющим спецификацию const, или ссылку на объект
такого типа можно привести в ссылку на объект с типом без const.
Получившаяся в результате ссылка будет настроена на исходный
объект. В результате попытки изменить этот объект с помощью
такой ссылки или указателя может возникнуть особая ситуация или
он будет таким же, как при обращении с помощью исходной ссылки
или указателя к объекту, тип которого не содержит const. Возникнет
ли особая адресная ситуация зависит от реализации.
Указатель на объект типа со спецификацией volatile можно привести
к указателю на объект типа без volatile. В результате получится
указатель, настроенный на исходный объект. Объект типа с volatile
или ссылку на такой объект можно привести к ссылке на объект с типом
без volatile.
Операции указатель-на-член применяются слева направо.
выражение-pm:
выражение-приведения
выражение-pm .* выражение-приведения
выражение-pm ->* выражение-приведения
Бинарная операция .* связывает свой второй операнд, который должен
иметь тип "указатель на член класса T", с первым операндом, имеющим
тип класс T или такой класс, для которого T является однозначно
определенным и достижимым базовым классом. Результатом будет объект
или функция с типом, задаваемым вторым операндом.
Бинарная операция ->* связывает свой второй операнд, который должен
иметь тип "указатель на член класса T", с первым операндом, имеющим
тип "указатель на T" или тип "указатель на класс, для которого T
является однозначно определенным и достижимым базовым классом".
Результатом будет объект или функция с типом, задаваемым вторым
операндом.
Если результат .* или ->* есть функция, то его можно использовать
только в качестве операнда операции вызова функции (), например,
операция
(ptr_to_obj->*ptr_to_mfct)(10);
приводит к вызову функции-члена, обозначенной ptr_to_mfct, для
объекта, на который настроен указатель ptr_to_obj. Результат
операции .* или ->* является адресом, если второй операнд есть
адрес.
Мультипликативные операции *, /, и % выполняются слева направо.
Мультипликативное-выражение:
выражение-pm
мультипликативное-выражение * выражение-pm
мультипликативное-выражение / выражение-pm
мультипликативное-выражение % выражение-pm
Операнды операций * и / должны иметь арифметический тип, операнды
для % должны быть целочисленного типа. Обычные арифметические
преобразования ($$R.4.5) производятся над операндами и определяют
тип результата.
Бинарная операция * обозначает умножение.
Бинарная операция / вычисляет частное, а бинарная операция %
вычисляет остаток от деления первого выражения на второе. Если
второй операнд у / или % есть 0, результат неопределен, иначе
(a/b)*b + a%b должно равняться a. Если оба операнда неотрицательны,
то таким же будет и результат, в противном случае знак результата
определяется реализацией.
R.5.7 Аддитивные операции
Аддитивные операции + и - выполняются слева направо, при этом
происходят обычные арифметические преобразования ($$R.4.5)
операндов арифметического типа.
аддитивное-выражение:
мультипликативное-выражение
аддитивное выражение + мультипликативное-выражение
аддитивное-выражение - мультипликативное-выражение
Операнды должны быть арифметического типа или типа указателя.
Результатом операции + является сумма операндов. Можно складывать
указатель на объект в массиве и значение любого целочисленного типа.
Результатом будет указатель того же типа, что и исходный указатель,
но он будет настроен на другой объект массива
с заданным смещением от исходного объекта. Так, если P
есть указатель на объект массива, выражение P+1 является указателем
на следующий объект массива. Если же получившийся в результате
сложения указатель вышел за границы массива, результат будет
неопределенным, кроме случая, когда указатель настроен на первый адрес
больший верхней границы массива.
Результатом операции - будет разность операндов. Значение
любого целочисленного типа можно вычитать из указателя, при этом
применяются те же преобразования, что и для операции +.
Никакие другие сочетания типов для указателей не допустимы.
Если вычитаются два указателя на объекты одного типа, результатом
будет целочисленное значение со знаком, которое показывает на сколько
объектов этого типа отстоят друг от друга указуемые объекты. Указатели
на соседние элементы массива отстоят на 1. Тип результата зависит от
реализации, но он должен быть определен как ptrdiff_t в стандартном
заголовочном файле <stddef.h>. Результат не определен, если указатели
не настроены на элементы одного массива. Если P есть указатель
на последний элемент массива, то (P+1) - 1 есть P.
Операции сдвигов << и >> выполняются слева направо.
сдвиговое-выражение:
аддитивное-выражение
сдвиговое-выражение << аддитивное выражение
сдвиговое-выражение >> аддитивное выражение
Операнды должны быть целочисленного типа, и над ними производятся
стандартные целочисленные преобразования. Тип результата совпадает
с типом преобразованного левого операнда. Результат не определен,
если правый операнд отрицателен или больше или равен числу разрядов
в двоичном представлении преобразованного левого операнда.
Значением выражения E1<<E2 будет E1 (рассматриваемое как набор
разрядов), сдвинутое влево на E2 разрядов, причем освободившиеся
разряды заполняются нулями. Значением выражения E1>>E2 будет E1,
сдвинутое вправо на E2 разрядов. Если E1 беззнакового типа или
имеет неотрицательное значение, гарантируется, что сдвиг вправо
- логический (заполнение нулями), иначе результат зависит от реализации.
Операции отношения выполняются слева направо, но этот факт мало что
дает, ибо выражение a<b<c означает (a<b)<c, а вовсе не (a<b)&&(b<c).
выражение-отношения:
сдвиговое-выражение
выражение-отношения < сдвиговое-выражение
выражение-отношения > сдвиговое-выражение
выражение-отношения <= сдвиговое-выражение
выражение-отношения >= сдвиговое-выражение
Операнды должны быть арифметического типа или типа указателей.
Операции < (меньше чем), > (больше чем), <= (меньше или равно) и
>= (больше или равно) дают результат 0, если указанное отношение
не выполняется, и 1, если оно выполняется. Тип результата int.
Над арифметическими операндами выполняются обычные арифметические
преобразования. Над указателями выполняются обычные преобразования
указателей. Предполагается, что любой указатель можно сравнить
с выражением, имеющим результат 0, и любой указатель можно сравнить
с указателем, имеющим тип void* (в этом случае указатель сначала
преобразуется к типу void*). Указатели на объекты или функции
одного типа (после преобразования указателей) можно сравнивать,
результат зависит от взаимного расположения в памяти объектов или
функций.
Два указателя на один и тот же объект считаются равными. Если
два указателя настроены на нестатические члены одного объекта, то
указатель, настроенный на член, описанный позднее, считается
большим, при условии, что члены не имеют разных спецификаций
указатель-доступа ($$R.11.1), а класс не является объединением.
Если два указателя настроены на нестатические члены одного объекта
и спецификации указателей-доступа ($$R.11.1) этих членов различны,
результат будет не определен. Если два указателя настроены на члены
(данные) одного и того же объединения, они считаются равными. Если два
указателя настроены на элементы одного массива или смотрят за границу
массива, то указатель, настроенный на элемент с большим индексом,
будет большим. Все другие сравнения указателей определяются
реализацией.
выражение-равенства:
выражение-отношения
выражение-равенства == выражение-отношения
выражение-равенства != выражение-отношения
Операции == (равно) и != (не равно) аналогичны операциям
отношения, за исключением того, что их приоритет ниже. (Таким образом,
операция a<b == c<d дает результат 1, если выражения a<b и c<d
имеют одно и то же значение.)
Кроме этого, можно сравнивать указатели на члены одного типа.
Производятся преобразования указателя на член ($$R.4.8). Указатель
на член можно сравнить с выражением-константой, которое дает
результат 0.
выражение-И:
выражение-равенства
выражение-И & выражение-равенства
Выполняются обычные арифметические преобразования, результат -
поразрядная функция И от операндов. Операция применима только к
целочисленным операндам.
выражение-исключающего-ИЛИ:
выражение-И
выражение-исключающего-ИЛИ ^ выражение-И
Выполняются обычные арифметические преобразования, результат -
поразрядная исключающая функция ИЛИ от операндов. Операция применима
только к целочисленным операндам.
выражение-ИЛИ:
выражение-исключающего-ИЛИ
выражение-ИЛИ | выражение-исключающего-ИЛИ
Выполняются обычные арифметические преобразования, результат -
поразрядная функция ИЛИ от операндов. Операция применима только
к целочисленным типам.
логическое-выражение-И:
выражение-ИЛИ
логическое-выражение-И && выражение-ИЛИ
Операции && выполняются слева направо. Такая операция дает результат
1, если оба операнда ее отличны от нуля, иначе результат - 0. В
отличие от & при операции && гарантируется вычисление слева направо,
более того, второй операнд не вычисляется, если первый операнд равен 0.
Операнды не обязательно имеют одинаковый тип, но каждый должен быть
арифметического типа или типа указателя. Тип результата int. Все
побочные эффекты вычисления первого выражения могут возникать до
вычисления второго выражения.
логическое-выражение-ИЛИ:
логическое-выражение-И
логическое-выражение-ИЛИ || логическое-выражение-И
Операции || выполняются слева направо. Результат операции 1, если
один из ее операндов отличен от нуля, иначе результат - 0. В отличие
от | при операции || гарантируется вычисление слева направо, более
того, второй операнд не вычисляется, если значение первого операнда
отлично от нуля.
Операнды не обязательно имеют одинаковый тип, но каждый должен быть
арифметического типа или типа указателя. Тип результата int. Все
побочные эффекты вычисления первого выражения могут возникать до
вычисления второго выражения.
выражение-условия:
логическое-выражение-ИЛИ
логическое-выражение-ИЛИ ? выражение : выражение-условия
Условные выражения выполняются слева направо. Первое выражение должно
быть арифметического типа или типа указателя. Оно вычисляется, и,
если результат его отличен от нуля, то результатом условного выражения
будет значение второго выражения, иначе результат - значение третьего
выражения. Все побочные эффекты вычисления первого выражения могут
возникать до вычисления второго или третьего выражения.
Если второе и третье выражение арифметического типа, и типы их
совпадают, то таким же будет и тип результата, если они различаются, то
выполняются обычные арифметические преобразования, чтобы привести их
к общему типу. Если второе и третье выражение являются
указателями или выражением-константой, дающим результат 0, выполняются
преобразования указателей, чтобы привести результаты выражений к
общему типу. Если второе и третье выражение являются ссылками,
выполняется преобразование ссылок, чтобы привести их к общему типу.
Если второе и третье выражение имеют тип void, общий тип
будет void. Если второе и третье выражение имеют один тип
класс T, общим типом будет T. Иначе, выражение считается недопустимым.
Тип результата есть общий тип. Вычисляется только второе или третье
выражение (но не оба). Результат будет адресом, если второй и
третий операнд одного типа и являются адресами.
Существует несколько операций присваивания, все они выполняются
справа налево. Для всех них требуется, чтобы левым операндом был
изменяемый адрес. Тип выражения присваивания совпадает с типом
левого операнда. Результат операции присваивание - значение,
хранящееся в левом операнде после того как произошло присваивание.
Результат является адресом.
выражение-присваивания:
выражение-условия
унарное-выражение операция-присваивания выражение-присваивания
операция-присваивания: один из
= *= /= %= += -= >>= <<= &= ^= |=
При простом присваивании (=) значение выражения заменяет собой значение
объекта, с которым сопоставляется левый операнд. Если оба операнда
арифметического типа, правый операнд, прежде чем произойдет
присваивание, преобразуется к типу левого операнда. Неявные
преобразования к типу перечисления ($$R.7.2) не производятся, поэтому
если левый операнд имеет тип перечисления, правый операнд должен
быть таким же. Если левый операнд имеет тип указателя, правый
операнд должен быть типа указателя или выражением-константой, дающим