简体   繁体   English

std::vector 初始化元素的移动/复制构造函数

[英]std::vector initialization move/copy constructor of the element

I have this piece of code:我有这段代码:

#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)}; 
}

The output is what I expect (compiled with g++ -std=c++11 --no-elide-constructors , same output without the flag) output 是我所期望的(用g++ -std=c++11 --no-elide-constructors编译,相同的 output 没有标志)

ctor
move ctor
dtor
dtor

Now instead of using push_back initialize directly the vector v as现在不使用push_back而是直接将向量v初始化为

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

I do not understand why I get the outputs:我不明白为什么我得到输出:

1) (without --no-elide-constructors ) 1) (没有--no-elide-constructors )

ctor
move ctor
copy ctor
dtor
dtor
dtor

2) (with --no-elide-constructors ) 2)(使用--no-elide-constructors

ctor
move ctor
move ctor
copy ctor
dtor
dtor
dtor
dtor

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.在第二种情况下,当编译器不执行省略时,我完全不知道为什么 move ctor 被调用两次。 Any ideas?有任何想法吗?

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

Here you're calling the vector constructor that takes an std::initializer_list .在这里,您正在调用带有std::initializer_list的向量构造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.初始值设定项列表只允许对其元素进行const访问,因此vector必须将每个元素从initializer_list复制到其自己的存储中。 That's what causes the call to the copy constructor.这就是导致调用复制构造函数的原因。

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

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. std::initializer_list<E>类型的对象是从初始化列表构造的,就好像实现分配了一个包含N const E类型元素的临时数组,其中N是初始化列表中的元素数。

See alsohttps://tristanbrindle.com/posts/beware-copies-initializer-list另见https://tristanbrindle.com/posts/beware-copies-initializer-list


As for the extra move constructor call with -fno-elide-constructors , this was discussed in another answer a couple of days ago.至于使用-fno-elide-constructors的额外移动构造函数调用,几天前在另一个答案中讨论过。 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.似乎 g++ 对我在上面引用的同一部分中的标准中显示的initializer_list的示例实现采用了一种非常直接的方法。

The same example, when compiled using clang , doesn't produce the extra move constructor call.同样的例子,当使用 clang 编译时,不会产生额外的移动构造函数调用。

The containers try very hard to make sure they remain usable should an exception occur.如果发生异常,容器会非常努力地确保它们仍然可用。 As part of this, they'll only use std::move internally if your class' move constructor is exception safe.作为其中的一部分,如果您的类的移动构造函数是异常安全的,他们只会std::move内部使用std::move If it is not, (or it can't tell), it will copy just to be safe.如果不是,(或者它不能告诉),它会复制只是为了安全。

The correct move operations are正确的移动操作是

Foo(Foo&&) noexcept {cout << "move ctor" << endl;}
Foo& operator=(Foo&&) noexcept {cout << "move assn" << endl;}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 c ++ copy constructor vs std :: vector的move构造函数 - c++ copy constructor vs move constructor for std::vector 如何强制 std::vector 使用移动构造函数而不是复制构造函数? - How to force std::vector to use move constructor instead of the copy one? 如何在std :: vector中存储没有复制或移动构造函数的对象? - How to store objects without copy or move constructor in std::vector? c2280 std :: vector的默认构造函数尽管具有移动构造函数,但仍需要元素的复制构造函数 - c2280 default constructor for std::vector requires copy constructor for elements despite having move constructor std :: vector行为,移动并复制 - std::vector behavior, move and copy 使用std :: vector移动和复制语义 - move and copy semantics with the std::vector 当 std::vector 重新分配其内存数组时,使用的是复制构造函数还是移动构造函数? - When std::vector reallocate its memory array, is copy constructor or move constructor used? 复制与移动 std::pair 支撑初始化 - Copy vs move in std::pair braced initialization 为什么std :: vector在初始化时强制复制? - Why does std::vector enforce copy on initialization? 向量移动构造函数比复制构造函数慢 - Vector move constructor slower than copy constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM