列表初始化和复制删除

List initialization and copy elision

本文关键字:删除 复制 初始化 列表      更新时间:2023-10-16

考虑以下示例:

#include <cstdlib>
struct A
{
    A(int, char*){};
    A(const A&){ printf("copy-ctorn"); }
};
int main()
{
    A x = A(5, nullptr);
}

根据(c++ 11标准的)8.5.16,

    A x = A(5, nullptr);

被视为

    A x(A(5, nullptr));

(即。然后根据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类型的对象)。

这个答案显然是错误的,这让我很惊讶。请看评论。我认为[dcl.init]的第一个和第四个要点。

表示(1)直接调用构造函数(或执行聚合初始化),而不需要临时调用。

标准中没有任何内容保证(1)和(2)避免临时的。它们都是复制初始化,(1)是由[dcl.init]定义的复制列表初始化。列表]p1:

list初始化可以发生在直接初始化或复制初始化上下文中;直接初始化上下文中的列表初始化称为直接列表初始化,复制初始化上下文中的列表初始化称为复制列表初始化

在这两种情况下都是复制初始化,而[dcl。Init]表示可能涉及移动(可以省略)。

8.5/14,15:

形式出现的初始化

T x = a;

[…]称为复制初始化。

表单

中的初始化

T x(a);

T x{a};

[…]称为直接初始化。

如果你的编译器不够聪明,不能总是省略临时,那么为了确保列表初始化没有临时,你可以使用直接列表初始化,即

A x{5, nullptr};