复制初始化

来自cppreference.com
< cpp‎ | language

从另一对象初始化一个对象

目录

[编辑] 语法

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

catch (T object)

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

[编辑] 解释

复制初始化在下列情况进行:

1) 当声明一个非引用类型 T 的具名变量(自动、静态或线程局域),带后随表达式的等号构成的初始化器时。
2) (C++11 前)当声明一个标量类型 T 的具名变量,带由后随花括号环绕表达式的等号构成的初始化器时(注意:从 C++11 开始,这被分类为列表初始化,且不允许窄化转换)。
3) 当按值传递参数到函数时
4) 当从返回一个值的函数返回
5) 当以值抛出捕获一个异常时
6) 作为聚合体初始化的一部分,初始化提供了初始化器的每个元素

复制初始化的效应为:

  • 首先,若 T 为类类型且初始化器为纯右值表达式,而其无 cv 资格的类型是与 T 相同的类,则初始化器表达式自身,而非从其实质化的临时量,被用于初始化目标对象:见复制省略
(C++17 起)
  • T 为类类型且 other 的类型的无 cv 限定版本是 T 或是从 T 导出的类,则检测 T非显式构造函数,并由重载解决选择最佳匹配。然后调用构造函数初始化该对象。
  • T 为类类型,且 other 的无 cv 限定版本不是 T 或从 T 导出者,或若 T 是非类类型,但 other 的类型为类类型,则检测能从 other 的类型转换到 T (或从 T 导出的类型,若 T 是类类型且转换函数可用)的 用户定义转换序列,并通过重载解决选择最佳者。转换结果,若使用转换构造函数则为纯右值临时量 (C++17 前)纯右值表达式 (C++17 起),随后被用于直接初始化该对象。最后一步通常会被优化掉,且转换结果直接构造于分配给目标对象的内存上,但要求适合的构造函数(移动或复制)可用,即使不使用它。 (C++17 前)
  • 否则(若 Tother 的类型均不是类类型),若有需要,则使用标准转换,将 other 的值转换成 T 的无 cv 限定版本。

[编辑] 注意

复制初始化不如直接初始化自由: explicit 构造函数不是转换构造函数,且不为复制初始化所考虑。

struct Exp { explicit Exp(const char*) {} }; // 不可从 const char* 转换
Exp e1("abc");  // OK
Exp e2 = "abc"; // 错误,复制初始化不考虑 explicit 构造函数
 
struct Imp { Imp(const char*) {} }; // 可从 const char* 转换
Imp i1("abc");  // OK
Imp i2 = "abc"; // OK

另外,复制初始化中的隐式转换必须直接从初始化器生成 T ,然而直接初始化期待从初始化器到 T 构造函数参数的隐式转换。

struct S { S(std::string) {} }; // 可从 std::string 转换
S s("abc"); // OK:从 const char[4] 转换到 std::string
S s = "abc"; // 错误:无从 const char[4] 到 S 的转换
S s = "abc"s; // OK:从 std::string 转换到 S

other 是右值表达式,则重载解决选择移动构造函数并在复制初始化期间调用它。没有类似移动初始化的项目。

隐式转换以复制初始化的方式定义:若 T 类型对象能以表达式 E 复制初始化,则 E 可被隐式转换成 T

等号 = 在具名变量的复制初始化中与赋值运算符无关。赋值运算符重载对复制初始化无效。

[编辑] 示例

#include <string>
#include <utility>
#include <memory>
 
int main()
{
    std::string s = "test"; // OK:构造函数非 explicit
    std::string s2 = std::move(s); // 此复制初始化进行移动
 
//  std::unique_ptr<int> p = new int(1); // 错误:构造函数为 explicit
    std::unique_ptr<int> p(new int(1)); // OK:直接初始化
 
    int n = 3.14;    // 浮点-整数转换
    const int b = n; // const 不影响
    int c = b;       // …无论何种方式
}


[编辑] 参阅