Namespaces
Variants

Direct-initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Инициализирует объект из явного набора аргументов конструктора.

Содержание

Синтаксис

T object ( arg );

T object ( arg1, arg2, ... );

(1)
T object { arg }; (2) (since C++11)
T ( other )

T ( arg1, arg2, ... )

(3)
static_cast< T >( other ) (4)
new T ( args, ... ) (5)
Class :: Class () : member ( args, ... ) { ... } (6)
[ arg ]() { ... } (7) (since C++11)
**Примечание:** В соответствии с требованиями: - HTML теги и атрибуты сохранены без изменений - Текст внутри тегов ` `, `
`, `` не переведен
- C++ специфические термины не переведены
- Сохранено оригинальное форматирование

Объяснение

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

1) Инициализация с непустым заключенным в скобки списком выражений или списками инициализации в фигурных скобках (начиная с C++11) .
2) Инициализация объекта неклассового типа с помощью одного инициализатора в фигурных скобках (примечание: для классовых типов и других случаев использования braced-init-list см. list-initialization ) (since C++11) .
3) Инициализация prvalue временного объекта (до C++17) результирующего объекта prvalue (начиная с C++17) с помощью function-style cast или со списком выражений в скобках.
4) Инициализация временного prvalue (до C++17) результирующего объекта prvalue (начиная с C++17) с помощью выражения static_cast .
5) Инициализация объекта с динамической продолжительностью хранения с помощью new-expression с инициализатором.
6) Инициализация базового класса или нестатического члена с помощью списка инициализации конструктора.
7) Инициализация членов объекта замыкания из переменных, захваченных по копии в лямбда-выражении.

Эффекты прямой инициализации:

  • Если T является типом массива,
  • программа является некорректно сформированной.
(до C++20)
struct A
{
    explicit A(int i = 0) {}
};
A a[2](A(1)); // OK: initializes a[0] with A(1) and a[1] with A()
A b[2]{A(1)}; // error: implicit copy-list-initialization of b[1]
              //        from {} selected explicit constructor
(начиная с C++20)
  • Если T является типом класса,
  • если инициализатор является prvalue выражением, тип которого совпадает с классом T (игнорируя cv-квалификаторы), то сам инициализатор, а не временный объект, материализованный из него, используется для инициализации целевого объекта.
    (До C++17 компилятор мог исключать конструкцию из временного prvalue в этом случае, но соответствующий конструктор всё равно должен быть доступен: см. copy elision )
(начиная с C++17)
  • конструкторы T анализируются, и наилучшее соответствие выбирается с помощью разрешения перегрузки. Затем конструктор вызывается для инициализации объекта.
  • в противном случае, если тип назначения является (возможно, cv-квалифицированным) агрегатным классом, он инициализируется, как описано в aggregate initialization , за исключением того, что сужающие преобразования разрешены, designated initializers не допускаются, время жизни временного объекта, привязанного к ссылке, не продлевается, скобки не опускаются, и любые элементы без инициализатора являются value-initialized .
struct B
{
    int a;
    int&& r;
};
int f();
int n = 10;
B b1{1, f()};            // OK, lifetime is extended
B b2(1, f());            // well-formed, but dangling reference
B b3{1.0, 1};            // error: narrowing conversion
B b4(1.0, 1);            // well-formed, but dangling reference
B b5(1.0, std::move(n)); // OK
(since C++20)
  • В противном случае, если T является неклассовым типом, но исходный тип - классовый, рассматриваются функции преобразования исходного типа и его базовых классов (при их наличии), и наилучшее соответствие выбирается с помощью разрешения перегрузки. Выбранное пользовательское преобразование затем используется для преобразования выражения инициализатора в инициализируемый объект.
  • В противном случае, если T является bool , а исходный тип - std::nullptr_t , значение инициализируемого объекта равно false .
  • В противном случае, стандартные преобразования используются, если необходимо, для преобразования значения other в версию T без cv-квалификаторов, и начальное значение инициализируемого объекта является (возможно преобразованным) значением.

Примечания

Прямая инициализация более разрешительна, чем копирующая инициализация: копирующая инициализация рассматривает только не- explicit конструкторы и неявные пользовательские conversion functions , тогда как прямая инициализация рассматривает все конструкторы и все пользовательские функции преобразования.

В случае неоднозначности между объявлением переменной с использованием синтаксиса прямой инициализации (1) (с круглыми скобками) и объявлением функции , компилятор всегда выбирает объявление функции. Это правило разрешения неоднозначности иногда оказывается неинтуитивным и получило название most vexing parse .

#include <fstream>
#include <iterator>
#include <string>
int main()
{
    std::ifstream file("data.txt");
    // Следующее является объявлением функции:
    std::string foo1(std::istreambuf_iterator<char>(file),
                     std::istreambuf_iterator<char>());
    // Объявляет функцию с именем foo1, возвращаемый тип которой std::string,
    // первый параметр имеет тип std::istreambuf_iterator<char> и имя "file",
    // второй параметр не имеет имени и имеет тип std::istreambuf_iterator<char>(),
    // который переписывается в тип указателя на функцию std::istreambuf_iterator<char>(*)()
    // Исправление для до C++11 (для объявления переменной) - добавить дополнительные скобки вокруг одного
    // из аргументов:
    std::string str1((std::istreambuf_iterator<char>(file)),
                      std::istreambuf_iterator<char>());
    // Исправление для после C++11 (для объявления переменной) - использовать list-инициализацию для любого
    // из аргументов:
    std::string str2(std::istreambuf_iterator<char>{file}, {});
}

Пример

#include <iostream>
#include <memory>
#include <string>
struct Foo
{
    int mem;
    explicit Foo(int n) : mem(n) {}
};
int main()
{
    std::string s1("test"); // конструктор из const char*
    std::string s2(10, 'a');
    std::unique_ptr<int> p(new int(1));  // OK: явные конструкторы разрешены
//  std::unique_ptr<int> p = new int(1); // ошибка: конструктор явный
    Foo f(2); // f прямо инициализируется:
              // параметр конструктора n копируется из rvalue 2
              // f.mem прямо инициализируется из параметра n
//  Foo f2 = 2; // ошибка: конструктор явный
    std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem  << '\n';
}

Вывод:

test aaaaaaaaaa 1 2

Смотрите также