Инициализация копированием
Инициализирует объект из другого объекта.
Синтаксис
T object = other; |
(1) | |
T object = {other}; |
(2) | (до C++11) |
f(other) |
(3) | |
return other; |
(4) | |
throw object;
|
(5) | |
T array[N] = {other-sequence}; |
(6) |
Объяснение
Инициализация копированием выполняется в следующих ситуациях:
T объявляется с инициализатором, состоящим из знака равенства, за которым следует выражение.T объявляется с инициализатором, состоящим из знака равенства, за которым следует выражение в фигурных скобках (Примечание: начиная с C++11, это классифицируется как инициализация списком, и сужение типа не допускается).Эффекты инициализации копированием:
|
(с C++17) |
- В противном случае, если
T— тип класса, а тип other без квалификаторов cv —Tили класс, производный отT, рассматриваются неявные конструкторыTи выбирается наиболее подходящий по принципу разрешения перегрузки. Затем вызывается этот конструктор для инициализации объекта. - В противном случае, если
T— тип класса, а тип other без квалификаторов cv неTили не производный отT, или еслиT— не тип класса, но тип other — тип класса, рассматриваются пользовательские последовательности преобразований, которые могут преобразовать тип other вT(или в тип, производный отT, еслиT— тип класса и доступна функция преобразования) и выбирается лучшая из них по принципу разрешения перегрузки. Результат преобразования, который является временным объектом-выражением-справа(до C++11)временным объектом-выражением-справа(с C++11)(до C++17)выражением-справа(с C++17) типаTбез квалификаторов cv, если использовался конструктор преобразования, затем используется для прямой инициализации объекта. Обычно последний шаг оптимизируется, и результат преобразования создается непосредственно в памяти, выделенной для целевого объекта, но необходим доступный конструктор (перемещения или копирования), хотя он и не используется.(до C++17) - В противном случае (если ни
T, ни тип other не являются типами классов), при необходимости используются стандартные преобразования для преобразования значения other в типTбез квалификаторов cv.
Примечания
Инициализация копированием менее гибкая, чем прямая инициализация: явные конструкторы не являются конструкторами преобразования и не рассматриваются при инициализации копированием.
struct Exp { explicit Exp(const char*) {} }; // not convertible from const char*
Exp e1("abc"); // OK
Exp e2 = "abc"; // Error, copy-initialization does not consider explicit constructor
struct Imp { Imp(const char*) {} }; // convertible from const char*
Imp i1("abc"); // OK
Imp i2 = "abc"; // OKКроме того, неявное преобразование при инициализации копированием должно генерировать T непосредственно из инициализатора, в то время как, например, прямая инициализация ожидает неявное преобразование из инициализатора в аргумент конструктора T.
struct S { S(std::string) {} }; // implicitly convertible from std::string
S s("abc"); // OK: conversion from const char[4] to std::string
S s = "abc"; // Error: no conversion from const char[4] to S
S s = "abc"s; // OK: conversion from std::string to SЕсли other — выражение-справа, при разрешении перегрузки будет выбран конструктор перемещения и вызван во время инициализации копированием. Это все еще считается инициализацией копированием; нет специального термина (например, инициализация перемещением) для этого случая.
Неявное преобразование определяется в терминах инициализации копированием: если объект типа T может быть инициализирован копированием с помощью выражения E, то E неявно преобразуется в T.
Знак равенства, =, при инициализации копированием именованной переменной не связан с оператором присваивания. Перегрузки оператора присваивания не влияют на инициализацию копированием.
Пример
#include <memory>
#include <string>
#include <utility>
struct A
{
operator int() { return 12;}
};
struct B
{
B(int) {}
};
int main()
{
std::string s = "test"; // OK: constructor is non-explicit
std::string s2 = std::move(s); // this copy-initialization performs a move
// std::unique_ptr<int> p = new int(1); // error: constructor is explicit
std::unique_ptr<int> p(new int(1)); // OK: direct-initialization
int n = 3.14; // floating-integral conversion
const int b = n; // const doesn't matter
int c = b; // ...either way
A a;
B b0 = 12;
// B b1 = a; // < error: conversion from 'A' to non-scalar type 'B' requested
B b2{a}; // < identical, calling A::operator int(), then B::B(int)
B b3 = {a}; // <
auto b4 = B{a}; // <
// b0 = a; // < error, assignment operator overload needed
[](...){}(c, b0, b3, b4); // pretend these variables are used
}Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применён к | Поведение, опубликованное | Правильное поведение |
|---|---|---|---|
| CWG 5 | C++98 | квалификация cv целевого типа применяется к временной переменной, инициализированной конструктором преобразования |
временная переменная не имеет cv-квалификаций |
| CWG 177 | C++98 | категория значения временной переменной, созданной при инициализации копированием объекта класса, не определена |
определена как выражение-справа |
См. также
- исключение копирования
- конструктор преобразования
- копирующее присваивание
- конструктор копирования
- конструктор по умолчанию
- деструктор
explicit- инициализация
- присваивание перемещением
- конструктор перемещения
new
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/copy_initialization