2. Если один из операндов имеет тип unsigned long
, то другой преобразовывается в тип unsigned long
. В противном случае, если один из операндов имеет тип long int
, а другой — unsigned int
, значение типа unsigned int
преобразуется в значение типа long int
, при условии, что тип long int
может представить все значения типа unsigned int
. В противном случае оба операнда преобразовываются в тип unsigned long int
. В противном случае, если один из операндов имеет тип long
, другой преобразовывается в тип long
. В противном случае, если другой операнд имеет тип unsigned
, другой преобразовывается в тип unsigned
. В противном случае оба операнда имеют тип int
.
Очевидно, что лучше не полагаться на слишком запутанные сочетания типов и минимизировать необходимость неявных преобразований.
A.5.2.3. Преобразования, определенные пользователем
Кроме стандартных преобразований и продвижений, программист может определить преобразования типов, определенных пользователем. Конструктор, принимающий один аргумент, определяет преобразование этого аргумента в значение своего типа. Если конструктор имеет спецификатор explicit
(см. раздел 18.3.1), то преобразование происходит, только если программист явно потребует его выполнить. В противном случае преобразование может быть неявным.
A.5.3. Константные выражения
int
. (Это немного упрощенное определение, но для большинства целей оно вполне подходит.) Рассмотрим пример.
const int a = 2*3;
const int b = a+3;
Константные выражения требуются в немногих случаях, например, при вычислении границ массивов, меток разделов case
, инициализаторов перечислений и шаблонных аргументов типа int
. Рассмотрим пример.
int var = 7;
switch (x) {
case 77: // OK
case a+2: // OK
case var: // ошибка (var — не константное выражение)
// ...
};
A.5.4. Оператор sizeof
В выражении sizeof(x)
аргумент x
может быть типом или выражением. Если x
— выражение, то значением sizeof(x)
является размер результирующего объекта. Если x
— тип, то значением sizeof(x)
является размер объекта типа x
. Размеры измеряются в байтах. По определению sizeof(char)==1
.
A.5.5. Логические выражения
В языке C++ предусмотрены логические операторы для целочисленных типов.
Эти операторы применяются к каждому биту своих операндов, в то время как логические операторы (&&
и ||
) трактуют число 0
как значение false
, а все — как true
. Определения этих операторов приведены ниже.
A.5.6. Операторы new и delete
Свободная память (динамическая память, или куча) выделяется с помощью оператора new
, а освобождается — с помощью оператора delete
(для индивидуальных объектов) или delete[]
(для массива).
Если память исчерпана, то оператор new
генерирует исключение bad_alloc
. В случае успеха операция new
выделяет как минимум один байт и возвращает указатель на объект, размещенный в памяти. Тип этого объекта определяется после выполнения оператора new
. Рассмотрим пример.
int* p1 = new int; // размещает (неинициализированное) число
// типа int
int* p2 = new int(7); // размещает число типа int,
// инициализированное
// числом 7
int* p3 = new int[100]; // размещает 100 (неинициализированных)
// чисел int
// ...
delete p1; // удаляет индивидуальный объект
delete p2;
delete[] p3; // удаляет массив
Если с помощью оператора new
вы размещаете в памяти объекты встроенного типа, они не будут инициализированы, если не указан инициализатор. Если с помощью оператора new
вы размещаете в памяти объекты класса, имеющего конструктор, то, если не указан инициализатор, будет вызван этот конструктор (см. раздел 17.4.4).
Оператор delete
вызывает деструкторы каждого операнда, если они есть. Обратите внимание на то, что деструктор может быть виртуальным (раздел A.12.3.1).
A.5.7. Операторы приведения
Существуют четыре оператора приведения к типу.