考虑以下示例:
#include <cstdlib>
struct A
{
A(int, char*){};
A(const A&){ printf("copy-ctor\n"); }
};
int main()
{
A x = A(5, nullptr);
}
根据8.5.16(C ++ 11标准)行
A x = A(5, nullptr);
被视为
A x(A(5, nullptr));
(即创建类型A的临时对象并将其传递给类型A的copy-ctor以初始化x)。然后根据12.8.31允许编译器(但不强制)执行称为“复制省略”的优化,以消除类型A的临时创建,这有效地使该行代码成为
A x(5, nullptr);
(即没有临时创建,没有复制的人称之为。)
现在,假设我在上面的示例中使用列表初始化,如下所示:
A x = {5, nullptr}; // (1)
或
A x = A{5, nullptr}; // (2)
有人可以引用来自C ++ 11标准的相应的法律图表来确认或否认(1)和/或(2)总是(即不仅当编译器可以做“复制省略”优化时)被视为
A x(5, nullptr);
(即直接调用A的第一个构造函数,不创建临时值,不执行类型A对象的复制)。
答案 0 :(得分:3)
这个答案显然是错误的,这让我感到惊讶。查看评论。我认为[dcl.init.list] / 3的第一和第四个要点是什么意思(1)直接调用构造函数(或执行聚合init),没有临时性。
标准中没有任何内容可以保证(1)和(2)避免临时性。它们都是复制初始化,(1)是[dcl.init.list] p1定义的复制列表初始化:
列表初始化可以在直接初始化或复制初始化上下文中进行;直接初始化上下文中的列表初始化称为 direct-list-initialization ,复制初始化上下文中的列表初始化称为 copy-list-initialization 。
在这两种情况下都是复制初始化,[dcl.init]表示可能涉及移动(可以省略)。
8.5/14,15
:
以
形式出现的初始化
T x = a;
[...]称为复制初始化。
表单中出现的初始化
T x(a);
T x{a};
[...]称为直接初始化。
如果你的编译器不够聪明,总是忽略临时,那么为了确保没有临时的列表初始化,你可以使用直接列表初始化,即
A x{5, nullptr};