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

标签 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

最佳答案

据我了解,initializer_list 通过常量引用传递所有内容。从一个 move 可能不安全。 vectorinitializer_list 构造函数将复制每个元素。

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

No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that initializer_list existed to keep an array of temporaries until they were move'd.

begin and end for initializer_list return const T *, so the result of move in your code is T const && — an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T const & because rvalues do bind to const lvalue references, and you will still see copy semantics.

Is it safe to move elements of a initializer list?

initializer_list only provides const access to its elements. You could use const_cast to make that code compile, but then the moves might end up with undefined behaviour (if the elements of the initializer_list are truly const). So, no it is not safe to do this moving. There are workarounds for this, if you truly need it.

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

The synopsis of in 18.9 makes it reasonably clear that elements of an initializer list are always passed via const-reference. Unfortunately, there does not appear to be any way of using move-semantic in initializer list elements in the current revision of the language.

questions regarding the design of std::initializer_list

From section 18.9 of the C++ Standard:

An object of type initializer_list provides access to an array of objects of type const E. [ Note: A pair of pointers or a pointer plus a length would be obvious representations for initializer_list. initializer_list is used to implement initializer lists as specified in 8.5.4. Copying an initializer list does not copy the underlying elements. — end note ]

I think the reason for most of these things is that std::initializer_list isn't actually a container. It doesn't have value semantics, it has pointer semantics. Which is made obvious by the last portion of the quote: Copying an initializer list does not copy the underlying elements. Seeing as they were intended solely for the purpose of initializing things, I don't think it's that surprising that you don't get all the niceties of more robust containers such as tuples.

如果我对最后一部分的理解正确,这意味着需要两组拷贝,因为 initializer_list 不复制底层元素。(前面的引述只是相关的如果您尝试在不复制元素的情况下使用 initializer_list。)

What is the underlying structure of std::initializer_list?

No, you can't move from the elements of an initializer_list, since elements of an initializer_list are supposed to be immutable (see the first sentence of the paragraph quoted above). That's also the reason why only const-qualified member functions give you access to the elements.


如果你愿意,你可以使用emplace_back:

vec.emplace_back(TS());
vec.emplace_back(TS());
vec.push_back(std::move(ts1));
vec.push_back(std::move(ts2));

关于c++ - 带大括号的 std::vector init 调用复制构造函数两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20501638/

相关文章:

c++ - 使用 C++ 插件从 chrome 浏览器下载并运行 exe

c++ - 如何让我的程序将用户登录到 Windows?

c++ - map 和 vector 上的 std::set_difference 会引发转换错误

c - C 中的逗号、圆括号和大括号之间的关系是什么?

coding-style - 为什么 Golang 强制大括号不在下一行?

c++ - regex c++-如何在字符串末尾保存多个标点符号?

c++ - Boost Asio 和 Beast multipart/form-data 从 Streambuf 保存二进制文件

c++ - C++ 中的缓冲区 vector

c++ - 与 const std::string 的 vector 相关的编译失败

c++ - 数组 C++ 中的大括号初始化