Пространства имён
Варианты
Действия

Прямая инициализация

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

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

Содержание

[править]Синтаксис

Tобъект(аргумент);

Tобъект(арг1, арг2, ...);

(1)
Tобъект{аргумент}; (2) (начиная с C++11)
T(другой)

T(арг1, арг2, ...)

(3)
static_cast<T>(другой) (4)
newT(аргументы, ...) (5)
Класс::Класс():элемент(аргументы, ...){...} (6)
[аргумент](){...} (7) (начиная с C++11)

[править]Объяснение

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

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

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

  • Если T является типом массива,
  • программа некорректна.
(до C++20)
struct A {explicit A(int i =0){}};   A a[2](A(1));// OK: инициализирует a[0] с помощью A(1) и a[1] с помощью A() A b[2]{A(1)};// ошибка: неявная инициализация списком копирования b[1]// из {} выбранного явного конструктора
(начиная с C++20)
  • Если T является типом класса,
  • если инициализатор представляет собой выражение prvalue, тип которого является тем же классом, что и T (игнорируя cv-квалификацию), само выражение инициализатора, а не материализованное из него временное выражение, используется для инициализации целевого объекта.
    (До C++17 компилятор мог исключить конструкцию из prvalue временного объекта в этом случае, но соответствующий конструктор должен быть доступен: смотрите пропуск копирования)
(начиная с C++17)
  • проверяются конструкторы T, и с помощью разрешения перегрузки выбирается наилучшее совпадение. Затем для инициализации объекта вызывается конструктор.
  • иначе, если целевой тип является агрегатным классом (возможно, cv-квалифицированным), он инициализируется, как описано в агрегатной инициализации, за исключением того, что сужающие преобразования разрешены, назначенные инициализаторы не разрешены, временная привязка к ссылке не продлевает время жизни, фигурные скобки не удаляются, а любые элементы без инициализатора инициализируются значением.
struct B {int a;int&& r;};   int f();int n =10;   B b1{1, f()};// OK, продлевается время жизни B b2(1, f());// верно, но висячая ссылка B b3{1.0, 1};// ошибка: сужающее преобразование B b4(1.0, 1);// верно, но висячая ссылка B b5(1.0, std::move(n));// OK
(начиная с C++20)
  • Иначе, если T является неклассовым типом, но исходный тип является классовым, проверяются функции преобразования исходного типа и его базовых классов, если таковые имеются, и путём разрешения перегрузки выбирается наилучшее совпадение. Затем выбранное определяемое пользователем преобразование используется для преобразования выражения инициализатора в инициализируемый объект.
  • Иначе, если T равно bool а исходный тип это std::nullptr_t, значением инициализированного объекта будет false.
  • Иначе при необходимости используются стандартные преобразования для преобразования значения другой в cv-неквалифицированную версию T, а начальным значением инициализируемого объекта является (возможно преобразованное) значение.

[править]Примечание

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

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

#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>());   // Исправление после С++11 (для объявления переменной) — используйте// инициализацию списком для любого из аргументов: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("тест");// конструктор из 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';}

Вывод:

тест aaaaaaaaaa 1 2

[править]Смотрите также

close