列表初始化和复制省略

时间:2014-03-17 15:25:56

标签: c++ c++11 language-lawyer copy-elision list-initialization

考虑以下示例:

#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对象的复制)。

1 个答案:

答案 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};