Инициализация значением
Это инициализация, выполняемая, когда объект создается с пустым инициализатором.
Синтаксис
T () | (1) | |
new T () | (2) | |
Класс::Класс(...) : член () { ... } | (3) | |
T объект {}; | (4) | (с C++11) |
T {} | (5) | (с C++11) |
new T {} | (6) | (с C++11) |
Класс::Класс(...) : член {} { ... } | (7) | (с C++11) |
Объяснение
Инициализация значением выполняется в этих ситуациях:
| 4) при объявлении именованного объекта (автоматического, статического или локального для потока) с инициализатором, состоящим из пары фигурных скобок. | (с C++11) |
Во всех случаях, если используется пустая пара фигурных скобок {} и T является агрегатным типом, выполняется агрегатная инициализация, а не инициализация значением.
| Если | (с C++11) |
Эффекты инициализации значением:
T является типом класса без конструктора по умолчанию или с явным(до C++11)явным или удаленным(с C++11) конструктором по умолчанию, объект инициализируется по умолчанию;T является типом класса с конструктором по умолчанию, который не явный(до C++11)не явный и не удаленный(с C++11) (то есть, это может быть класс с неявно определённым или по умолчанию определённым конструктором по умолчанию), объект инициализируется нулём и проверяются семантические ограничения для инициализации по умолчанию, и если T имеет нетривиальный конструктор по умолчанию, объект инициализируется по умолчанию;T является массивом, каждый элемент массива инициализируется значением;Примечания
Синтаксис T object(); не инициализирует объект; он объявляет функцию, которая не принимает аргументов и возвращает T. Способ инициализации именованной переменной значением до C++11 был T object = T();, который инициализирует значением временную переменную, а затем копирует ее в объект: большинство компиляторов оптимизируют копирование в этом случае.
Ссылки не могут быть инициализированы значением.
Как описано в функциональном преобразовании, синтаксис T() (1) запрещен для массивов, а синтаксис T{} (5) разрешен.
Все стандартные контейнеры (std::vector, std::list, и т. д.) инициализируют свои элементы значением при создании с единственным size_type аргументом или при увеличении вызовом resize(), если их выделение памяти не переопределяет поведение construct.
Стандарт гласит, что инициализация нулём не выполняется, если класс имеет явный или удалённый конструктор по умолчанию, что подразумевает, что выбор конструктора по умолчанию по разрешению перегрузки не рассматривается. Все известные компиляторы выполняют дополнительную инициализацию нулём, если выбран не удалённый конструктор по умолчанию.
struct A
{
A() = default;
template<class = void>
A(int = 0) {} // A has a user-provided default constructor, which is not selected
int x;
};
constexpr int test(A a)
{
return a.x; // the behavior is undefined if a's value is indeterminate
}
constexpr int zero = test(A());
// ill-formed: the parameter is not zero-initialized according to the standard,
// which results in undefined behavior that makes the program ill-formed in contexts
// where constant evaluation is required.
// However, such code is accepted by all known compilers.
void f()
{
A a = A(); // not zero-initialized according to the standard
// but implementations generate code for zero-initialization nonetheless
}Пример
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
struct T1
{
int mem1;
std::string mem2;
virtual void foo() {} // make sure T1 is not an aggregate
}; // implicit default constructor
struct T2
{
int mem1;
std::string mem2;
T2(const T2&) {} // user-provided copy constructor
}; // no default constructor
struct T3
{
int mem1;
std::string mem2;
T3() {} // user-provided default constructor
};
std::string s{}; // class => default-initialization, the value is ""
int main()
{
int n{}; // scalar => zero-initialization, the value is 0
assert(n == 0);
double f = double(); // scalar => zero-initialization, the value is 0.0
assert(f == 0.0);
int* a = new int[10](); // array => value-initialization of each element
assert(a[9] == 0); // the value of each element is 0
T1 t1{}; // class with implicit default constructor =>
assert(t1.mem1 == 0); // t1.mem1 is zero-initialized, the value is 0
assert(t1.mem2 == ""); // t1.mem2 is default-initialized, the value is ""
// T2 t2{}; // error: class with no default constructor
T3 t3{}; // class with user-provided default constructor =>
std::cout << t3.mem1; // t3.mem1 is default-initialized to indeterminate value
assert(t3.mem2 == ""); // t3.mem2 is default-initialized, the value is ""
std::vector<int> v(3); // value-initialization of each element
assert(v[2] == 0); // the value of each element is 0
std::cout << '\n';
delete[] a;
}Возможный вывод:
42
Отчеты об ошибках
Следующие исправления с изменениями поведения были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 178 | C++98 | инициализация значением не существовала; пустой инициализатор вызывал инициализацию по умолчанию (хотя new T() также выполняет инициализацию нулём) | пустой инициализатор вызывает инициализацию значением |
| CWG 543 | C++98 | инициализация значением для объекта класса без пользовательских конструкторов была эквивалентна инициализации значением каждого подобъекта (что не должно инициализировать нулём член с пользовательским конструктором по умолчанию) | инициализирует весь объект нулём, затем вызывает конструктор по умолчанию |
| CWG 1301 | C++11 | инициализация значением объединений с удалёнными конструкторами по умолчанию приводила к инициализации нулём | они инициализируются по умолчанию |
| CWG 1368 | C++98 | любой пользовательский конструктор вызывал пропуск инициализации нулём | только явный пользовательский конструктор по умолчанию пропускает инициализацию нулём |
| CWG 1502 | C++11 | инициализация значением объединения без пользовательского конструктора по умолчанию инициализировало только объект, несмотря на инициализаторы членов по умолчанию | выполняет инициализацию по умолчанию после инициализации нулём |
| CWG 1507 | C++98 | инициализация значением для объекта класса без пользовательских конструкторов не проверяла корректность конструктора по умолчанию, когда последний тривиален | проверяется корректность тривиального конструктора по умолчанию |
См. также
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/value_initialization