Spec-Zone.ru › C++

Инициализация значением

Это инициализация, выполняемая при создании объекта с пустым инициализатором.

Синтаксис

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)

Пояснение

Инициализация значением выполняется в следующих ситуациях:

1,5) при создании безымянного временного объекта с инициализатором, состоящим из пустой пары скобок или фигурных скобок(начиная с C++11);
2,6) при создании объекта с динамической длительностью хранения с помощью new-выражения с инициализатором, состоящим из пустой пары скобок или фигурных скобок(начиная с C++11);
3,7) при инициализации нестатического члена данных или базового класса с помощью инициализатора члена с пустой парой скобок или фигурных скобок(начиная с C++11);
4) при объявлении именованного объекта (автоматического, статического или локального для потока) с инициализатором, состоящим из пары фигурных скобок.

Во всех случаях, если используется пустая пара фигурных скобок {} и T является агрегатным типом, вместо инициализации значением выполняется агрегатная инициализация.

Если T — тип класса, у которого нет конструктора по умолчанию, но есть конструктор, принимающий std::initializer_list, выполняется инициализация списком.

(начиная с C++11)

Инициализация значением оказывает следующие эффекты:

  • Если T — тип класса (возможно, cv-квалифицированный):
    • Если при инициализации по умолчанию для T выбирается конструктор, и этот конструктор не является объявленным пользователем(до C++11)предоставленным пользователем(начиная с C++11), объект сначала инициализируется нулём.
    • В любом случае объект инициализируется по умолчанию.
  • В противном случае, если T является типом массива, каждый элемент массива инициализируется значением.
  • В противном случае объект инициализируется нулём.

Примечания

Синтаксис T object(); не инициализирует объект; он объявляет функцию без аргументов, возвращающую T. До C++11 именованную переменную можно было инициализировать значением с помощью T object = T();: в этом случае создаётся временный объект, инициализируемый значением, а затем объект копирующе инициализируется из него; большинство компиляторов оптимизируют копирование в этом случае.

Ссылки нельзя инициализировать значением.

Как описано в разделе приведение в стиле вызова функции, синтаксис 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() {} // 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 при инициализации значением объекта класса без каких-либо
предоставленных пользователем конструкторов не проверялась корректность
конструктора по умолчанию, если он был тривиальным
корректность тривиального
конструктора по умолчанию
проверяется
CWG 2820 C++98 инициализация по умолчанию после инициализации
нулём требовала нетривиальный конструктор
не требуется
CWG 2859 C++98 инициализация значением объекта класса могла включать
инициализацию нулём, даже если при инициализации по умолчанию
фактически не выбирался предоставленный пользователем конструктор
в этом случае
инициализация нулём
не выполняется

См. также

  • конструктор по умолчанию
  • explicit
  • агрегатная инициализация
  • инициализация списком

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/value_initialization

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API