Value-initialization
Это инициализация, выполняемая при создании объекта с пустым инициализатором.
Содержание |
Синтаксис
T
()
|
(1) | ||||||||
new
T
()
|
(2) | ||||||||
Class
::
Class
(
...
)
:
member
()
{
...
}
|
(3) | ||||||||
T
object
{};
|
(4) | (начиная с C++11) | |||||||
T
{}
|
(5) | (начиная с C++11) | |||||||
new
T
{}
|
(6) | (начиная с C++11) | |||||||
Class
::
Class
(
...
)
:
member
{}
{
...
}
|
(7) | (начиная с C++11) | |||||||
Объяснение
Инициализация значением выполняется в следующих ситуациях:
Во всех случаях, если используется пустая пара фигурных скобок
{}
и
T
является агрегатным типом,
агрегатная инициализация
выполняется вместо value-инициализации.
|
Если
|
(since C++11) |
Эффекты инициализации значением:
-
Если
Tявляется (возможно, cv-квалифицированным) классным типом:
-
-
Если default-инициализация для
Tвыбирает конструктор , и конструктор не является user-declared (до C++11) user-provided (начиная с C++11) , объект сначала подвергается zero-инициализации . - В любом случае, объект подвергается default-инициализации .
-
Если default-инициализация для
-
В противном случае, если
Tявляется типом массива, каждый элемент массива инициализируется по значению. - В противном случае объект инициализируется нулями.
Примечания
Синтаксис
T object
(
)
;
не инициализирует объект; он объявляет функцию, которая не принимает аргументов и возвращает
T
. Способ value-инициализации именованной переменной до C++11 был
T object
=
T
(
)
;
, который value-инициализирует временный объект и затем copy-инициализирует объект: большинство компиляторов
оптимизируют копирование
в этом случае.
Ссылки не могут быть инициализированы значением по умолчанию.
Как описано в разделе
function-style cast
, синтаксис
T
(
)
(1)
запрещён, если
T
обозначает тип массива, тогда как
T
{
}
(5)
разрешён.
Все стандартные контейнеры (
std::vector
,
std::list
, и т.д.) инициализируют свои элементы по значению при создании с единственным аргументом
size_type
или при увеличении размера через вызов
resize
(
)
, если только их аллокатор не изменяет поведение
construct
.
Пример
#include <cassert> #include <iostream> #include <string> #include <vector> struct T1 { int mem1; std::string mem2; virtual void foo() {} // гарантирует, что T1 не является агрегатом }; // неявный конструктор по умолчанию struct T2 { int mem1; std::string mem2; T2(const T2&) {} // пользовательский конструктор копирования }; // нет конструктора по умолчанию struct T3 { int mem1; std::string mem2; T3() {} // пользовательский конструктор по умолчанию }; std::string s{}; // класс => инициализация по умолчанию, значение равно "" int main() { int n{}; // скаляр => обнуляющая инициализация, значение равно 0 assert(n == 0); double f = double(); // скаляр => обнуляющая инициализация, значение равно 0.0 assert(f == 0.0); int* a = new int[10](); // массив => инициализация значением каждого элемента assert(a[9] == 0); // значение каждого элемента равно 0 T1 t1{}; // класс с неявным конструктором по умолчанию => assert(t1.mem1 == 0); // t1.mem1 обнуляется, значение равно 0 assert(t1.mem2 == ""); // t1.mem2 инициализируется по умолчанию, значение равно "" // T2 t2{}; // ошибка: класс без конструктора по умолчанию T3 t3{}; // класс с пользовательским конструктором по умолчанию => std::cout << t3.mem1; // t3.mem1 инициализируется по умолчанию в неопределенное значение assert(t3.mem2 == ""); // t3.mem2 инициализируется по умолчанию, значение равно "" std::vector<int> v(3); // инициализация значением каждого элемента assert(v[2] == 0); // значение каждого элемента равно 0 std::cout << '\n'; delete[] a; }
Возможный вывод:
42
Отчеты о дефектах
Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| CWG 178 | C++98 |
не существовало value-initialization; пустой инициализатор вызывал default-
initialization (хотя new T ( ) также выполняет zero-initialization) |
пустой инициализатор вызывает
value-initialization |
| CWG 543 | C++98 |
value-initialization для объекта класса без каких-либо
user-provided конструкторов была эквивалентна value- initialization каждого подобъекта (что не обязательно zero- initialize член с user-provided default constructor) |
zero-initializes
весь объект, затем вызывает default constructor |
| CWG 1301 | C++11 |
value-initialization объединений с удаленными
default constructors приводила к zero-initialization |
они
default-initialized |
| CWG 1368 | C++98 |
любой user-provided конструктор вызывал
пропуск zero-initialization |
только user-provided
default constructor пропускает zero-initialization |
| CWG 1502 | C++11 |
value-initializing объединения без user-provided
default constructor только zero-initialized объект, несмотря на default member initializers |
выполняет default-
initialization после zero-initialization |
| CWG 1507 | C++98 |
value-initialization для объекта класса без каких-либо
user-provided конструкторов не проверяла валидность default constructor когда последний является trivial |
валидность trivial
default constructor проверяется |
| CWG 2820 | C++98 |
default-initialization после zero-
initialization требовала non-trivial constructor |
не требуется |
| CWG 2859 | C++98 |
value-initialization для объекта класса могла включать
zero-initialization даже если default-initialization фактически не выбирает user-provided constructor |
нет
zero-initialization в этом случае |