带大括号的std :: vector init调用复制构造函数两次

时间:2013-12-10 17:48:02

标签: c++ stdvector curly-braces list-initialization

为什么当我使用大括号

初始化std :: vector时
std::vector<TS> vec {ts1, ts2};

编译器调用两次复制构造函数运算符?另一方面 - 使用push_back只调用一次。

#include <iostream>
#include <vector>
using namespace std;

struct TS{
    TS(){
        cout<<"default constructor\n";
    }

    TS(const TS &other) {
        cout<<"Copy constructor\n";
    }

    TS(TS &&other) noexcept{
        cout<<"Move constructor\n";
    }

    TS& operator=(TS const& other)
    {
        cout<<"Copy assigment\n";
        return *this;
    }

    TS& operator=(TS const&& other) noexcept
    {
        cout<<"Move assigment\n";
        return *this;
    }

    ~TS(){
        cout<<"destructor\n";
    }

};

int main() {
    TS ts1;
    TS ts2;
    cout<<"-----------------------------------------\n";
    std::vector<TS> vec {ts1, ts2};
    //vec.push_back(ts1);
    //vec = {ts1, ts2};
    cout<<"-----------------------------------------\n";



    return 0;
}

http://ideone.com/qcPG7X

2 个答案:

答案 0 :(得分:2)

根据我的理解,initializer_list通过const-reference传递所有内容。 move可能不安全。 initializer_list的{​​{1}}构造函数将复制每个元素。

以下是一些链接: initializer_list and move semantics

  

不,这不会按预期工作;你仍然会得到副本。我很漂亮   对此感到惊讶,因为我认为initializer_list存在   保留一系列临时工,直到他们搬家为止。

     

beginizer_list的开始和结束返回const T *,所以结果为   在你的代码中移动是T const&amp;&amp; - 不可变的右值引用。这样   表达不能有意义地移动。它将绑定到   T const&amp;类型的函数参数因为rvalues会绑定到const   左值引用,你仍然会看到复制语义。

Is it safe to move elements of a initializer list?

  

initializer_list仅提供对其元素的const访问。你可以   使用const_cast来编译代码,但随后移动可能会结束   未定义的行为(如果initializer_list的元素   是真正的const)。所以,做这个动作并不安全。有   如果你真的需要它,可以解决这个问题。

Can I list-initialize a vector of move-only type?

  

18.9的概要使其相当清楚   初始化列表的元素总是通过   常量引用。不幸的是,似乎没有任何方法   在当前的初始化列表元素中使用move-semantic   修订语言。

questions regarding the design of std::initializer_list

  

来自C ++标准的第18.9节:

     

类型为initializer_list的对象提供对const E类型对象数组的访问。[注意:一对指针或指针加上   长度将是initializer_list的明显表示。   initializer_list用于实现指定的初始化列表   在8.5.4。复制初始化列表不会复制基础   元素。 - 结束说明]

     

我认为大多数这些事情的原因是   std :: initializer_list实际上不是一个容器。它没有   值语义,它有指针语义。这是显而易见的   引用的最后一部分:复制初始化列表不会   复制基础元素。看来它们只是用于   初始化事物的目的,我不认为这是令人惊讶的   你没有得到更强大的容器的所有细节,如   元组。

如果我正确理解了最后一部分,则意味着需要两组副本,因为vector不复制基础元素。(之前的引用仅在您尝试时才有意义使用initializer_list而不复制元素。)

What is the underlying structure of std::initializer_list?

  

不,你不能从initializer_list的元素移动,因为   initializer_list的元素应该是不可变的(参见   上面引用的段落的第一句)。这也是原因   为什么只有const限定的成员函数才能让你访问   元件。


如果需要,可以使用initializer_list

emplace_back

答案 1 :(得分:1)

因为那里有两个元素。