Справочное руководство по C++ — страница 5 из 41

 (выражение)

 имя

Литерал является первичным выражением. Его тип определяется его видом (§R.2.5).

В теле нестатической функции-члена (§R.9.3) служебное слово this обозначает указатель на объект, к которому относится вызов функции. Служебное слово this нельзя использовать вне тела функции-члена класса.

Операция ::, за которой следует идентификатор или имя-операции-функции или уточненное-имя являются первичным выражением. Его тип задается описанием идентификатора, имени или имени-функции-операции. Результатом является идентификатор, имя или имя-функции-операции. Результат является адресом, если идентификатор является адресом. Идентификатор или имя-функции-операции должны иметь файловую область видимости. С помощью операции :: можно обращаться к типу, объекту, функции или элементу перечисления, даже если обозначающий их идентификатор является скрытым (§R.3.2).

Выражение в скобках является первичным выражением, тип и значение которого идентичны им же у выражения без скобок. Наличие скобок не влияет на то, является выражение адресом или нет.

Понятие имя - это определенное первичное-выражение, которое может появляться только после . и -› (§R.5.2.4):

имя:

 идентификатор

 имя-функции-операции

 имя-функции-преобразования

 ~имя-класса

 уточненное-имя

Идентификатор есть имя, при условии что он описан надлежащим образом (§R.7). Понятие имя-функции-операции описано в (§R.13.4), а понятие имя-функции-преобразования в (§R.12.3.2). Конструкция ~имя-класса обозначает деструктор (§R.12.4).

уточненное-имя:

 уточняющее-имя-класса :: имя

Понятие уточняющее-имя-класса, за которым следует :: и имя члена этого класса (§R.9.2), или члена базового по отношению к данному класса (§R.10) является уточненное-имя. Его тип есть тип члена, а результат выражения есть этот член. Результат является адресом, если таковым является член. Имя класса может быть скрыто другим именем (не типа), в таком случае все равно имя класса доступно и его можно использовать. Если используется имя-класса::имя-класса или имя-класса::~имя-класса, оба понятия имя-класса должны обозначать один и тот же класс. С помощью такой записи обозначаются конструкторы (§R.12.1) и деструкторы (§R.12.4) соответственно. Можно использовать уточняющие имена неоднократно, например, N1::N2::N3::n, чтобы обозначать вложенные типы (§R.9.7).

R.5.2 Постфиксные выражения

Постфиксные выражения применяются слева направо.

постфиксное-выражение:

 первичное-выражение

 постфиксное-выражение [выражение]

 постфиксное-выражение (список-выражений opt)

 имя-простого-типа (список-выражений opt)

 постфиксное-выражение . имя

 постфиксное-выражение -› имя

 постфиксное-выражение ++

 постфиксное-выражение --

список-выражений:

 выражение-присваивания

 список-выражений, выражение-присваивания

R.5.2.1 Индексация

Постфиксное выражение, за которым следует выражение в квадратных скобках, является постфиксным выражением. Интуитивный смысл его индексирование. Первое из выражений должно иметь тип "указатель на T", а второе быть целочисленного типа. Тип результата есть "T". Выражение E1[E2] совпадает (по определению) с выражением *((E1) + (E2)). Подробности операций * и + даны в §R.5.3 и §R.5.7, а массивы обсуждаются в §R.8.2.4.

R.5.2.2 Вызов функции

Вызов функции является постфиксным выражением, за которым следует, возможно пустой, список выражений в скобках, разделенных запятой. Эти выражения образуют фактические параметры функции. Постфиксное выражение должно иметь тип "функция, возвращающая T", "указатель на функцию, возвращающую T" или "ссылка на функцию, возвращающую T", а результат операции вызова имеет тип "T".

При вызове функции происходит инициализация каждого формального параметра (§R.8.4.3, §R.12.8, $$r.12.1) фактическим параметром. Производятся стандартные (§R.4) и заданные пользователем (§R.12.3) преобразования типа. В функции может изменяться значения непостоянных формальных параметров, но эти изменения не могут повлиять на значения фактических параметров, кроме того случая, когда формальный параметр имеет тип ссылки без спецификации const (§R.8.2.2). Если формальный параметр имеет тип ссылки при необходимости может создаваться временная переменная (§R.7.1.6, §R.2.5,§R.2.5.4,§R.8.2.4, §R.12.2). Добавим, что возможно изменение непостоянных объектов с помощью параметров-указателей.

Функцию можно описать таким образом, что она сможет использовать меньшее число параметров (определив параметры по умолчанию §R.8.2.6) или большее число параметров (с помощью эллипсиса … §R.8.2.5), чем было указано при определении функции (§R.8.3).

Функцию можно вызвать только, если описание ее доступно в той области видимости, где происходит вызов. Отсюда следует, всякий формальный параметр, соответствующий некоторому фактическому параметру, должен быть доступен, если не считать эллипсис (…).

Перед вызовом всякий фактический параметр типа float, для которого нет формального параметра, преобразуется к типу double, а типа char, short, перечисления или битовое поле, для которого нет формального параметра, преобразуется к типу int или unsigned согласно стандартным преобразованиям целочисленных (§R.4.1). Объект, являющийся классом и не имеющий описания формального параметра, передается при вызове как структура данных.

Объект, являющийся классом и имеющий описание формального параметра передается с помощью инициализации формального параметра фактическим параметром, которая происходит перед выполнением функции посредством вызова конструктора (§R.12.2, §R.12.8).

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

Допустимы рекурсивные вызовы.

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

R.5.2.3 Явные преобразования типа

Конструкция имя-простого-типа (§R.7.1.6), за которой следует список-выражений в скобках образует значение указанного типа с учетом списка выражений. Если список выражений содержит более одного значения, тип должен быть классом с конструктором, описанным соответствующим образом (§R.8.4, §R.12.1).

Конструкция имя-простого-типа (§R.7.1.6), за которой следует пара скобок (пустая), образует значение указанного типа. Если тип является классом с конструктором, описанным соответствующим образом, будет вызван этот конструктор, в противном случае результатом будет неопределенное значение указанного типа, см. так же (§R.5.4).

R.5.2.4 Доступ к члену класса

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

Постфиксное выражение, за которым следует стрелка (-›) и имя, является постфиксным выражением. Первое выражение должно быть указателем на объект типа класс, а имя должно быть именем члена этого класса. Результатом будет поименованный член объекта, на который настроен указатель и он будет адресом, если член является адресом. Значит выражение E1-›MOS тоже самое, что (*E1).MOS.

Обратите внимание, что "объекты типа класс" могут быть структурами (§R.9.2) или объединениями (§R.9.5). Классы обсуждаются в §R.9.

R.5.2.5 Инкремент и декремент

Значение, получаемое в результате применения постфиксной операции ++, есть значение операнда. Операнд должен быть изменяемым адресом. Тип операнда должен быть арифметический или тип указателя. После выборки результата (для дальнейшего использования) объект увеличивается на 1. Тип результата совпадает с типом операнда, но не является адресом (см. так же §R.5.7 и §R.5.17).

Постфиксная операция -- сводится к операции декремента (уменьшение на 1) и аналогична операции ++.

R.5.3 Унарные операции

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

унарное-выражение:

 постфиксное-выражение

 ++ унарное выражение

 -- унарное выражение

 унарная-операция выражение-приведения

 sizeof унарная-операция

 sizeof (имя-типа)

 выражение-размещения

 выражение-освобождения

унарная-операция: один из

 * & + - ! ~

Унарная операция * означает косвенность: выражение должно быть указателем, а результат является адресом, ссылающимся на объект, на который указывает выражение. Если тип выражения есть "указатель на T", то тип результата будет "T".

Результатом унарной операции & будет указатель на ее операнд. Операнд должен быть функцией или адресом или конструкцией уточненное-имя. Для первых двух случаев, если тип выражения есть "T", то тип результата будет "указатель на T". В частности, адрес объекта типа const T имеет тип const T*, тоже верно для volatile. Для случая уточненное имя если член класса "C" не является статическим и имеет тип "T", то тип результата операции будет "указатель на член C типа T". Для статических членов типа T результатом будет обычный "указатель на T". Адрес перегруженной функции (§R.13) можно брать только при инициализации или присваивании, в котором левая часть однозначно определяет какая версия перегруженной функции имеется ввиду ($R13.3).

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

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

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

Операнд операции логического отрицания ! должен иметь арифметический тип или быть указателем, результат равен 1, если значение операнда есть 0, и равен 0, если операнд не равен 0. Тип результата есть int.

Операнд операции ~ должен иметь целочисленный тип, результатом будет обращение двоичного представления операнда. Выполняются стандартные преобразования целочисленных. Тип результата есть тип преобразованного операнда.

R.5.3.1 Инкремент и декремент

Операнд префиксной операции ++ увеличивается на 1. Операнд должен быть изменяемым адресом. Тип операнда должен быть арифметическим или указателем. Результатом является новое значение операнда, оно считается адресом. Выражение ++x эквивалентно x+=1. Для уточнения преобразований можно обратиться к описанию сложения (§R.5.7) и операций присваивания (§R.5.17).

Префиксная операция -- сводится к уменьшению на 1 и выполняется аналогично префиксной операции ++.

R.5.3.2 Операция sizeof

Операция sizeof вычисляет размер своего операнда в байтах. Операнд должен быть или выражением, которое не вычисляется, или именем типа в скобках. Операцию sizeof нельзя применять к функции, битовому полю, неопределенному классу, типу void или к массиву с неуказанными границами индексов. Байт никак не определяется языком, кроме как результата операции sizeof, именно sizeof(char) есть 1.

Если операция применяется к ссылке, результатом будет размер объекта, на который настроена ссылка. Если она применяется к классу, результатом будет размер объекта этого класса в байтах с учетом всех дополнительных байтов, которые потребуется для размещения такого объекта в массиве. Размер любого класса или объекта класса больше нуля. В случае массива операция выдает полное число байтов в массиве. Отсюда следует, что размер массива из n элементов равен размеру элемента, умноженному на n.

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

Результатом операции будет константа типа size_t. Этот тип определен в стандартном заголовочном файле ‹stddef.h› и является зависящим от реализации беззнаковым целочисленным типом.

R.5.3.3 Операция new

Операция 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'

Символ * используется в описателе указателя, а не в качестве операции умножения.

R.5.3.4 Операция delete

Операция 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.4 Явное преобразование типа