std :: vector初始化移动/复制元素的构造函数 [英] std::vector initialization move/copy constructor of the element

查看:752
本文介绍了std :: vector初始化移动/复制元素的构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这段代码:

#include <iostream>
#include <vector>

using namespace std;

class Foo{
public:
    Foo() noexcept {cout << "ctor" << endl;}
    Foo(const Foo&) noexcept {cout << "copy ctor" << endl;}
    Foo(Foo&&) noexcept {cout << "move ctor" << endl;}

    Foo& operator=(Foo&&) noexcept {cout << "move assn" << endl; return *this;}
    Foo& operator=(const Foo&) noexcept {cout << "copy assn" << endl; return *this;}

    ~Foo() noexcept {cout << "dtor" << endl;}
};


int main()
{   
    Foo foo;

    vector<Foo> v;
    v.push_back(std::move(foo)); 

    // comment the above 2 lines and replace by
    // vector<Foo> v{std::move(foo)}; 
}

输出是我期望的(用 g ++ -std = c ++ 11 --no-elide-constructors ,没有标志的相同输出)

The output is what I expect (compiled with g++ -std=c++11 --no-elide-constructors, same output without the flag)

ctor
move ctor
dtor
dtor

使用 push_back 直接初始化向量 v

vector<Foo> v{std::move(foo)};

我不明白为什么得到输出:

I do not understand why I get the outputs:

1)(不含 - no-elide-constructors

ctor
move ctor
copy ctor
dtor
dtor
dtor

2)( - no-elide-constructors

ctor
move ctor
move ctor
copy ctor
dtor
dtor
dtor
dtor

在第一种情况下,为什么会调用copy ctor?在第二种情况下,当编译器不执行elision,我绝对不知道为什么move ctor被调用两次。有任何想法吗?

In the first case, why is the copy ctor invoked? And in the second case, when the compiler does not perform elision, I have absolutely no idea why the move ctor is invoked twice. Any ideas?

推荐答案

vector<Foo> v{std::move(foo)};

在这里你调用的矢量构造函数需要一个 std :: initializer_list 。初始化列表只允许 const 访问其元素,因此向量将必须从 initializer_list 到其自己的存储。这是调用复制构造函数的原因。

Here you're calling the vector constructor that takes an std::initializer_list. An initializer list only allows const access to its elements, so the vector is going to have to copy each element from the initializer_list to its own storage. That's what causes the call to the copy constructor.

§8.5.4/ 5 [dcl.init.list]

From §8.5.4/5 [dcl.init.list]


类型为 std :: initializer_list< E> 的对象是从初始化器列表构造的,实现分配了 N 类型 const E 的临时数组,其中 N 是初始化器列表中的元素数。

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated a temporary array of N elements of type const E, where N is the number of elements in the initializer list.






对于 -fno-elide-constructors 的额外移动构造函数调用,这在另一个回答几天前。看起来好像g ++对于在上面引用的标准中的标准中显示的 initializer_list 的示例实现非常字面。


As for the extra move constructor call with -fno-elide-constructors, this was discussed in another answer a couple of days ago. It seems as though g++ takes a very literal approach to the example implementation of an initializer_list shown in the standard in same section I've quoted above.

同样的例子,当使用clang编译时, t产生额外的移动构造函数调用。

The same example, when compiled using clang, doesn't produce the extra move constructor call.

这篇关于std :: vector初始化移动/复制元素的构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆