This question already has answers here:
How to enforce move semantics when a vector grows?

(3个答案)


去年关闭。




首先,我不会英语,所以我使用翻译。

该代码是支持 vector 中移动语义的代码。

创建单个 vector 并将Test对象插入push_back()方法的代码。

该代码的结果是,每次由于push_back()方法而添加Test对象时,都应该调用move构造函数,对吗?

但是,仅当插入新对象时,编译器才调用move构造函数,而旧对象则调用copy构造函数。

为什么会这样呢?我想念什么吗?
#include <iostream>
#include <vector>
using namespace std;

class Test
{
public:
    Test(int data1, int data2) :data1(data1), data2(data2)
    {
        cout << "Normal Constructor" << endl;
    }
    Test(const Test& src)
    {
        cout << "Copy Constructor" << endl;
        this->data1 = src.data1;
        this->data2 = src.data2;
    }
    Test(Test&& rhs)
    {
        cout << "Move Constructor" << endl;
        this->data1 = rhs.data1;
        this->data2 = rhs.data2;
        rhs.data1 = 0;
        rhs.data2 = 0;
    }
    Test& operator=(const Test& src)
    {
        if (this == &src)
            return *this;
        cout << "Copy assignment operator" << endl;
        this->data1 = src.data1;
        this->data2 = src.data2;
        return *this;
    }
    Test& operator=(Test&& rhs)
    {
        if (this == &rhs)
            return *this;
        cout << "Move assignment operator" << endl;
        this->data1 = rhs.data1;
        this->data2 = rhs.data2;
        rhs.data1 = 0;
        rhs.data2 = 0;
        return *this;
    }
    private:
        int data1, data2;
    };

int main()
{
    vector<Test> vec;
    for (int i = 0; i < 5; i++)
    {
        cout << "Iteration  " << i << endl;
        vec.push_back(Test(100, 100));
        cout << endl;
    }
}

最佳答案

std::vector选择复制构造函数而不是move构造函数的原因是您的move构造函数不是nothrow。为什么std::vector在乎?

好吧,std::vector具有一些异常安全保证。例如,参见 std::vector::push_back 的异常保证:



这意味着,当以某种方式引发异常时,它不会炸毁整个容器,在这种情况下,异​​常保证甚至可以保证错误的插入对vector完全没有影响。

拥有一个非noexcept move构造函数是一个问题,因为如果会引发重新分配,则std::vector无法回到有效状态,因为它可能已经将其一半的项移到了另一半上,然后尝试将它们移回旧的内存位置也可能会抛出异常。复制不会出现此问题,因为旧项目保持完好无损,因此,如果有副本抛出,std::vector只需要破坏到目前为止已复制的所有(新)项目并放弃。您作为集合的用户,可以保证插入或重新分配不当都会使所有其他项目保持完整。这就是为什么noexcept保证只有在保证移动不会抛出的情况下才使用move-constructor的原因。

关于c++ - 支持 vector 中的移动语义,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55153410/

10-11 02:03
查看更多