Copy-initialization
Initializes an object from another object.
Syntax
T object = other;
|
(1) | ||||||||
T object = { other};
|
(2) | (until C++11) | |||||||
f( other)
|
(3) | ||||||||
return other;
|
(4) | ||||||||
throw object;
|
(5) | ||||||||
T array[ N] = { other-sequence};
|
(6) | ||||||||
Explanation
Copy-initialization is performed in the following situations:
T
is declared with the initializer consisting of an equals sign followed by an expression.T
is declared with the initializer consisting of an equals sign followed by a brace-enclosed expression (Note: as of C++11, this is classified as list initialization
The effects of copy-initialization are:
|
(since C++17) |
- Otherwise, if
T
is a class type and the cv-unqualified version of the type of other isT
or a class derived fromT
, the non-explicit constructors ofT
- Otherwise, if
T
is a class type, and the cv-unqualified version of the type of other is notT
or derived fromT
, or ifT
is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other toT
(or to a type derived fromT
ifT
is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a rvalue temporary(until C++11) prvalue temporary(since C++11)(until C++17) prvalue expression(since C++17) of the cv-unqualified version ofT
if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out (until C++17)
- Otherwise (if neither
T
nor the type of other are class types), standard conversions are used, if necessary, to convert the value of other to the cv-unqualified version ofT
Notes
Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors
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
In addition, the implicit conversion in copy-initialization must produce T
directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of 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
If other is an rvalue expression, a move constructor
Implicit conversion is defined in terms of copy-initialization: if an object of type T
can be copy-initialized with expression E
, then E
is implicitly convertible to T
The equals sign, =
, in copy-initialization of a named variable is not related to the assignment operator. Assignment operator overloads have no effect on copy-initialization.
Example
#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 }
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 5 | C++98 | the cv-qualification of the destination type is applied to the temporary initialized by a converting constructor |
the temporary is not cv-qualified |
CWG 177 | C++98 | the value category of the temporary created during copy-initialization of a class object is unspecified |
specified as rvalue |