首页 > 解决方案 > C++ 在 std::vector 中移动构造函数多次调用

问题描述

我编写了简单的代码来理解移动语义和移动构造函数。

#include <iostream>
#include <vector>

using namespace std;



class Data
{
public:

    Data(int sz)
    {
        cout << "ctor" << endl;
        buffer = new int[sz];
        size = sz;
    }
    Data(Data& other)
    {
        size = other.size;
        cout << "copy ctor" << endl;
        buffer = new int[size];
        memcpy(buffer, other.buffer, size * sizeof(int)); //deep copy
    }
    Data(Data&& r)
    {
        size = r.size;
        cout << "move ctor" << endl;
        buffer = r.buffer;

    }

private:
    double bigValue;
    int* buffer;
    int size;

};



int main(void) 
{

    auto f = []() { cout << "---------------------\n"; };
     

    vector<Data> data;

    data.push_back(  move( Data(1)  ) ); // move constructor called once
    f();

    data.push_back(  move( Data(2)  ) ); // move constructor called twice
    f();

    data.push_back(  move( Data(3)  ) ); // move constructor called 3 times
    f();


    int stop; cin >> stop;

    return 0;
}

我看到了一些奇怪的东西:

每次我调用 push_back 时,都会执行另一个移动构造函数调用。

附上程序输出

在此处输入图像描述

我需要帮助来理解这个奇怪的输出。

谢谢。

标签: c++vectormove

解决方案


当向量增长时,它必须重新分配。向量从容量 0 开始,仅在需要时增加容量。通常情况下,容量会增加 10 倍,2以确保所承诺的时间复杂度push_back。其他因素也还可以。

您看到的是向量在重新分配时将元素移动到内存中的不同位置。

当您预先分配足够的空间时,您看不到额外的移动:

vector<Data> data;
data.reserve(5);           // <------------------- reserve
data.push_back(  move( Data(1)  ) );
f();
data.push_back(  move( Data(2)  ) );
f();
data.push_back(  move( Data(3)  ) );
f();

输出

ctor
move ctor
---------------------
ctor
move ctor
---------------------
ctor
move ctor
---------------------

PS:正如评论中提到的,演员通过std::move是多余的。data.push_back( Data(1) );你可以用, 粗鲁的口语来达到同样的效果,因为Data(1)已经是暂时的,push_back并且会在可能的情况下移动。此外(也来自评论),当您想在适当位置构建一个元素时,您应该使用emplace_back而不是首先在向量外部创建一个临时对象然后将其移入。std::move在这里没有伤害,但不必要的临时对象可能很昂贵,具体取决于如何移动元素的成本很高。


推荐阅读