调用 Copy 构造函数时发生什么类型的初始化?

What Type of Initialization Occurs When Calling Copy Constructor?

提问人:zemageht 提问时间:7/20/2020 最后编辑:songyuanyaozemageht 更新时间:7/20/2020 访问量:186

问:

考虑下面的简单结构(默认为显式)。

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 的答案。如适用,请提供参考资料。 谢谢。

C++ 初始 C++17 复制构造函数 列表初始化

答:

4赞 songyuanyao 7/20/2020 #1

给定 ,是从 的返回值直接初始化 的。和 是一样的,是从 直接列表初始化的。foo c{bar()};cbar()foo d{c};dc

  1. 使用 braced-init-list(即可能为空的括号括起来的表达式列表或嵌套的 braced-init-lists)初始化命名变量

作为效果,由于强制复制省略(从 C++17 开始),语句中的复制构造和初始化被省略,由默认构造函数直接构造。对于 ,选择复制构造函数来构造 。foo c{bar()};returnccfoo d{c};d

顺便说一句:在 中,执行复制初始化,由于强制复制省略(从 C++17 开始)复制构造被省略,返回值由默认构造函数直接初始化(从 C++20 开始)。(在 C++20 之前,它将被聚合初始化bar()return foo{};

评论

0赞 dfrib 7/20/2020
我可能是错的,但没有使用聚合初始化,就像聚合一样(至少在 C++20 之前)。我相信您可以显式删除所有构造函数,同时仍然在 C++17 中保持格式良好(保证复制省略,即使删除了 ctor 也是 C++20 之前的聚合)。return foo{};foofooreturn foo{};foo
0赞 dfrib 7/20/2020
(请参阅P1008R1了解删除此聚合特性的 C++20 更改)。
0赞 songyuanyao 7/20/2020
@dfri我明白你的意思。答案已修订。
0赞 Nicol Bolas 7/20/2020 #2

调用 Copy 构造函数时发生什么类型的初始化?

你的问题是倒退的,最终无法回答。

初始化形式确定用于获取初始值设定项表达式并从中初始化对象的各种步骤。初始化有多种形式,其中大多数都具有某种机制,最终会导致复制构造函数调用。列表初始化、直接初始化、复制初始化、聚合初始化,当然,只要有正确的初始值设定项,所有这些都可以调用复制构造函数。

因此,您无法根据调用了复制构造函数这一事实来知道使用了哪种初始化形式。

使用的初始化形式由初始化对象的语法决定。

foo c{bar()};
foo d{c};

它们使用相同的初始化语法,因此它们使用相同的初始化形式。这是直接初始化,但由于初始值设定项是 braced-init-list (),因此很快就会变成 direct-list-initialization。{}

foo e = d;

此语法调用复制初始化。