考虑下面的简单结构(默认为显式结构)。
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
直接列表初始化的。
因此,对于foo c{bar()};
,由于强制复制省略(自c++17以来),省略了return
语句中的复制构造和c
的初始化,c
直接由默认构造函数构造。 对于foo d{c};
,选择复制构造函数来构造d
。
注意:在bar()
中,返回foo{};
执行复制初始化,由于强制复制省略(自C++17以来),复制构造被省略,返回值直接由默认构造函数初始化(自C++20以来)。 (在C++20之前,它将被聚合初始化。)
调用复制构造函数时发生什么类型的初始化?
你的问题是反向的,最终无法回答。
初始化表单确定用于获取初始值设定项表达式并从中初始化对象的各种步骤。 初始化有多种形式,其中大多数都有某种机制,最终可以导致复制构造函数调用。 列表初始化,直接初始化,复制初始化,聚合初始化,所有这些都可以调用复制构造函数,当然,只要有正确的初始值设定项。
因此,您不能仅从调用了复制构造函数这一事实就知道使用了哪种初始化形式。
所使用的初始化形式由初始化对象的语法决定。
foo c{bar()};
foo d{c};
它们使用相同的初始化语法,因此它们使用相同的初始化形式。 这是直接初始化,但是因为初始值设定项是带括号的init-list({}
),所以会很快变成直接列表初始化。
foo e = d;
此语法调用复制初始化。