Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/copy initialization"

From cppreference.com
< cpp‎ | language
m (Syntax: Rm some spaces, rm semicolons after function call and catch-clause, change other to object in catch-clause)
(Link update.)
 
(34 intermediate revisions by 18 users not shown)
Line 1: Line 1:
{{title|copy initialization}}
+
{{title|Copy-initialization}}
 
{{cpp/language/initialization/navbar}}
 
{{cpp/language/initialization/navbar}}
Initializes an object from another object
+
Initializes an object from another object.
  
 
===Syntax===
 
===Syntax===
 
 
{{sdsc begin}}
 
{{sdsc begin}}
{{sdsc | num=1 | {{spar|T}} {{spar|object}} {{ttb|{{=}}}} {{spar|other}}{{ttb|;}} }}
+
{{sdsc|num=1|{{spar|T}} {{spar|object}} {{ttb|1==}} {{spar|other}}{{ttb|;}}}}
{{sdsc | num=2 | {{spar|f}}{{ttb|(}}{{spar|other}}{{ttb|)}} }}
+
{{sdsc|num=2|notes={{mark until c++11}}|{{spar|T}} {{spar|object}} {{ttb|1==}} {{ttb|{}}{{spar|other}}{{ttb|};}}}}
{{sdsc | num=3 | {{ttb|return}} {{spar|other}}{{ttb|;}} }}
+
{{sdsc|num=3|{{spar|f}}{{ttb|(}}{{spar|other}}{{ttb|)}}}}
{{sdsc | num=4 | {{ttb|catch (}}{{spar|T}} {{spar|object}}{{ttb|)}} }}
+
{{sdsc|num=4|{{ttb|return}} {{spar|other}}{{ttb|;}}}}
{{sdsc | num=5 | {{spar|T}} {{spar|array}}{{ttb|[}}{{spar|N}}{{ttb|] {{=}} {}}{{spar|other}}{{ttb|};}}}}
+
{{sdsc|num=5|{{ttb|throw }}{{spar|object}}{{ttb|;}}
 +
{{ttb|catch (}}{{spar|T}} {{spar|object}}{{ttb|)}}}}
 +
{{sdsc|num=6|{{spar|T}} {{spar|array}}{{ttb|[}}{{spar|N}}{{ttb|1=] = {}}{{spar|other-sequence}}{{ttb|};}}}}
 
{{sdsc end}}
 
{{sdsc end}}
  
 
===Explanation===
 
===Explanation===
 +
Copy-initialization is performed in the following situations:
 +
@1@ When a named variable (automatic, static, or thread-local) of a non-reference type {{tt|T}} is declared with the initializer consisting of an equals sign followed by an expression.
 +
@2@ {{mark until c++11}} When a named variable of a scalar type {{tt|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 {{rlp|list initialization}}, and narrowing conversion is not allowed).
 +
@3@ When {{rlp|operator other#Built-in function call operator|passing an argument}} to a function by value.
 +
@4@ When {{rlp|return|returning}} from a function that returns by value.
 +
@5@ When {{rlp|throw|throwing}} or {{rlp|catch|catching}} an exception by value.
 +
@6@ As part of {{rlp|aggregate initialization}}, to initialize each element for which an initializer is provided.
  
Copy initialization is performed in the following situations:
+
The effects of copy-initialization are:
@1@ when a named variable (automatic, static, or thread-local) of a non-reference type {{tt|T}} is declared with the initializer consisting of an equals sign followed by an expression.
+
@2@ when passing an argument to a function by value
+
@3@ when returning from a function that returns by value
+
@4@ when catching an exception by value
+
@5@ as part of [[cpp/language/aggregate_initialization|aggregate initialization]], to initialize each element for which an initializer is provided
+
  
The effects of copy initialization are:
+
{{rev begin}}
 +
{{rev|since=c++17|
 +
* First, if {{tt|T}} is a class type and the initializer is a {{rlp|value category|prvalue}} expression whose cv-unqualified type is the same class as {{tt|T}}, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see {{rlp|copy elision}}.
 +
}}
 +
{{rev end}}
  
* If {{tt|T}} is a class type and the type of {{spar|other}} is cv-unqualified version of {{tt|T}} or a class derived from {{tt|T}}, the constructors of {{tt|T}} are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
+
* Otherwise, if {{tt|T}} is a class type and the cv-unqualified version of the type of {{spar|other}} is {{tt|T}} or a class derived from {{tt|T}}, the {{rlp|converting constructor|non-explicit constructors}} of {{tt|T}} are examined and the best match is selected by overload resolution. That constructor is then called to initialize the object.
  
* If {{tt|T}} is a class type, and the type of {{spar|other}} is different, or if {{tt|T}} is non-class type, but the type of {{spar|other}} is a class type, [[cpp/language/implicit_cast|user-defined conversion sequences]] that can convert from the type of {{spar|other}} to {{tt|T}} (or to a type derived from T if T 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 prvalue temporary if a {{rlp|converting constructor}} was used, is then used to [[cpp/language/direct_initialization|direct-initialize]] the object. The last step is usually [[cpp/language/copy_elision|optimized out]] and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used.
+
* Otherwise, if {{tt|T}} is a class type, and the cv-unqualified version of the type of {{spar|other}} is not {{tt|T}} or derived from {{tt|T}}, or if {{tt|T}} is non-class type, but the type of {{spar|other}} is a class type, {{rlp|implicit cast|user-defined conversion sequences}} that can convert from the type of {{spar|other}} to {{tt|T}} (or to a type derived from {{tt|T}} if {{tt|T}} 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 {{rev inl|until=c++11|rvalue temporary}}{{rev inl|since=c++11|until=c++17|prvalue temporary}}{{rev inl|since=c++17|prvalue expression}} of the cv-unqualified version of {{tt|T}} if a {{rlp|converting constructor}} was used, is then used to {{rlp|direct initialization|direct-initialize}} the object. {{rev inl|until=c++17|The last step is usually {{rlp|copy elision|optimized out}} and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used.}}
  
* Otherwise (if neither {{tt|T}} nor the type of {{spar|other}} are class types), [[cpp/language/implicit_cast|standard conversions]] are used, if necessary, to convert the value of {{spar|other}} to the cv-unqualified version of {{tt|T}}.
+
* Otherwise (if neither {{tt|T}} nor the type of {{spar|other}} are class types), {{rlp|implicit cast|standard conversions}} are used, if necessary, to convert the value of {{spar|other}} to the cv-unqualified version of {{tt|T}}.
  
 
===Notes===
 
===Notes===
Copy-initialization is less permissive than direct-initialization: copy-initialization only considers non-explicit constructors and user-defined conversion functions.
+
Copy-initialization is less permissive than direct-initialization: {{rlp|explicit|explicit constructors}} are not {{rlp|converting constructor}}s and are not considered for copy-initialization.
 +
{{source|1=
 +
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
  
If {{spar|other}} is an rvalue expression, [[cpp/language/move_constructor|move constructor]] will be selected by overload resolution and called during copy-initialization. There is no such term as move-initialization.
+
struct Imp { Imp(const char*) {} }; // convertible from const char*
 +
Imp i1("abc");  // OK
 +
Imp i2 = "abc"; // OK
 +
}}
  
[[cpp/language/implicit_cast|Implicit conversion]] is defined in terms of copy-initialization: if an object of type {{tt|T}} can be copy-initialized with expression {{tt|E}}, then {{tt|E}} is implicitly convertible to {{tt|T}}.
+
In addition, the implicit conversion in copy-initialization must produce {{tt|T}} directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of {{tt|T}}'s constructor.
 +
{{source|1=
 +
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
 +
}}
  
The equals sign, {{ttb|{{=}}}}, in copy-initialization of a named variable is not related to the assignment operator. Assignment operator overloads have no effect on copy-initialization.
+
If {{spar|other}} is an rvalue expression, a {{rlp|move constructor}} will be selected by overload resolution and called during copy-initialization. This is still considered copy-initialization; there is no special term (e.g., move-initialization) for this case.
  
===Example===
+
{{rlp|implicit cast|Implicit conversion}} is defined in terms of copy-initialization: if an object of type {{tt|T}} can be copy-initialized with expression {{tt|E}}, then {{tt|E}} is implicitly convertible to {{tt|T}}.
  
 +
The equals sign, {{ttb|1==}}, in copy-initialization of a named variable is not related to the assignment operator. Assignment operator overloads have no effect on copy-initialization.
 +
 +
===Example===
 
{{example
 
{{example
|
+
|
| code=
+
|code=
 +
#include <memory>
 
#include <string>
 
#include <string>
 
#include <utility>
 
#include <utility>
#include <memory>
+
 
+
struct A
 +
{
 +
    operator int() { return 12;}
 +
};
 +
 +
struct B
 +
{
 +
    B(int) {}
 +
};
 +
 
int main()
 
int main()
 
{
 
{
     std::string s = "test"; // OK: constructor is non-explicit
+
     std::string s = "test";       // OK: constructor is non-explicit
 
     std::string s2 = std::move(s); // this copy-initialization performs a move
 
     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); // error: constructor is explicit
     std::unique_ptr<int> p(new int(1)); // OK: direct-initialization
+
     std::unique_ptr<int> p(new int(1)); // OK: direct-initialization
 
+
 
     int n = 3.14;    // floating-integral conversion
 
     int n = 3.14;    // floating-integral conversion
 
     const int b = n; // const doesn't matter
 
     const int b = n; // const doesn't matter
 
     int c = b;      // ...either way
 
     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
 
}
 
}
| output=
 
 
}}
 
}}
 +
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=cwg|dr=5|std=C++98|before=the cv-qualification of the destination type is applied to<br>the temporary initialized by a converting constructor|after=the temporary is not cv-qualified}}
 +
{{dr list item|wg=cwg|dr=177|std=C++98|before=the value category of the temporary created during<br>copy-initialization of a class object is unspecified|after=specified as rvalue}}
 +
{{dr list end}}
  
 
===See also===
 
===See also===
* [[cpp/language/default_initialization|default initialization]]
+
* {{rlp|copy elision}}
* [[cpp/language/direct_initialization|direct initialization]]
+
* {{rlp|converting constructor}}
* [[cpp/language/aggregate_initialization|aggregate initialization]]
+
* {{rlp|copy assignment}}
* [[cpp/language/list_initialization|list initialization]]
+
* {{rlp|copy constructor}}
 +
* {{rlp|default constructor}}
 +
* {{rlp|destructor}}
 +
* {{rlpt|explicit}}
 +
* {{rlp|initialization}}
 +
** {{rlp|aggregate initialization}}
 +
** {{rlp|constant initialization}}
 +
** {{rlp|default initialization}}
 +
** {{rlp|direct initialization}}
 +
** {{rlp|initializer list}}
 +
** {{rlp|list initialization}}
 +
** {{rlp|reference initialization}}
 +
** {{rlp|value initialization}}
 +
** {{rlp|zero initialization}}
 +
* {{rlp|move assignment}}
 +
* {{rlp|move constructor}}
 +
* {{rlpt|new}}
  
[[de:cpp/language/copy initialization]]
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
[[es:cpp/language/copy initialization]]
+
[[fr:cpp/language/copy initialization]]
+
[[it:cpp/language/copy initialization]]
+
[[ja:cpp/language/copy initialization]]
+
[[pt:cpp/language/copy initialization]]
+
[[ru:cpp/language/copy initialization]]
+
[[zh:cpp/language/copy initialization]]
+

Latest revision as of 22:17, 5 June 2024

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
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
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Initializes an object from another object.

Contents

[edit] Syntax

T object = other; (1)
T object = {other}; (2) (until C++11)
f(other) (3)
return other; (4)
throw object;

catch (T object)

(5)
T array[N] = {other-sequence}; (6)

[edit] Explanation

Copy-initialization is performed in the following situations:

1) When a named variable (automatic, static, or thread-local) of a non-reference type T is declared with the initializer consisting of an equals sign followed by an expression.
2) (until C++11) When a named variable of a scalar type 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, and narrowing conversion is not allowed).
3) When passing an argument to a function by value.
4) When returning from a function that returns by value.
5) When throwing or catching an exception by value.
6) As part of aggregate initialization, to initialize each element for which an initializer is provided.

The effects of copy-initialization are:

  • First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision.
(since C++17)
  • Otherwise, if T is a class type and the cv-unqualified version of the type of other is T or a class derived from T, the non-explicit constructors of T are examined and the best match is selected by overload resolution. That constructor is then called to initialize the object.
  • Otherwise, if T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T 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 to T (or to a type derived from T if T 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 of T if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used.(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 of T.

[edit] Notes

Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.

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's constructor.

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 will be selected by overload resolution and called during copy-initialization. This is still considered copy-initialization; there is no special term (e.g., move-initialization) for this case.

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.

[edit] 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
}

[edit] 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

[edit] See also