考虑下面的简单结构(默认为显式(。
struct foo {
foo() = default;
foo(const foo&) = default;
};
foo bar() {
return foo{}; // return does copy init
}
下面会进行什么样的初始化?
foo a; // default init
foo b{}; // value initialization
foo c{bar()}; // ?? mandatory copy elision. is this considered direct init? so copy init to return from
// bar(), then direct init to init c?
foo d{c}; // ?? copy constructor called. is this considered direct init or copy init?
foo e = d; // copy init
寻找C++17的答案。请尽可能提供参考资料。谢谢
给定foo c{bar()};
,c
是从bar()
的返回值初始化的直接列表。和foo d{c};
一样,d
是从c
初始化的直接列表。
- 初始化具有支撑init列表的命名变量(即,可能是空的、用大括号括起来的表达式列表或嵌套的支撑init列表(
因此,对于foo c{bar()};
,由于强制的副本省略(由于C++17(,省略了return
语句中的副本构造和c
的初始化,c
由默认构造函数直接构造。对于foo d{c};
,选择复制构造函数来构造d
。
BTW:在bar()
中,return foo{};
执行复制初始化,由于强制的复制省略(由于C++17(,复制构造被省略,返回值由默认构造函数直接初始化(由于C++20(。(在C++20之前,它将被聚合初始化。(
调用复制构造函数时发生什么类型的初始化?
你的问题是倒退的,最终无法回答。
初始化窗体确定用于获取初始值设定项表达式并从中初始化对象的各种步骤。初始化有多种形式,其中大多数都有一些机制,可以最终导致复制构造函数调用。列表初始化、直接初始化、复制初始化、聚合初始化,所有这些都可以调用复制构造函数,当然,只要初始化器正确。
因此,您无法从调用复制构造函数的事实中知道哪种初始化形式是单独使用的。
所使用的初始化形式由初始化对象的语法决定。
foo c{bar()};
foo d{c};
它们使用相同的初始化语法,因此使用相同形式的初始化。这是直接初始化,但因为初始化器是一个支持的init列表({}
(,所以很快就会变成直接列表初始化。
foo e = d;
此语法调用复制初始化。