C++11 多重移动构造函数调用

C++11 Multiple move constructor call

我用 g++ -std=c++11 file.cpp 编译了这个,我对 C++ 中的移动构造函数感到很困惑。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class P {
public:
    string* ptr_;
    P(string name) { ptr_ = new string(name); }
    ~P() { delete ptr_; }
    P(P&& pother) : ptr_(move(pother.ptr_)) { 
        cout<<"move"<<endl; 
        pother.ptr_=nullptr; 
    }
    void print() {cout << *ptr_ << endl;}
};

int main()
{
    vector<P> ppl;
    ppl.push_back(P("Jojo"));
    ppl.push_back(P("Jojo"));
    ppl.push_back(P("Jojo"));
}

这个程序的输出是:

$ ./a.out 
move
move
move
move
move
move

为什么移动构造函数在这里被调用了6次?

因为std::vector::push_back导致重新分配;当新的 size() 大于 capacity() 时,vector 分配新的底层存储,并且所有当前元素都通过移动构造函数移动到新存储。在重新分配期间移动元素会导致多次调用移动构造函数。

标准没有明确规定容量如何增长;我想这里每次重新分配都会加倍,然后

ppl.push_back(P("Jojo")); // 0 element(s) moved, 1 element added, 1 move(s) in all; size=1, capacity=1
ppl.push_back(P("Jojo")); // 1 element(s) moved, 1 element added, 2 move(s) in all; size=2, capacity=2
ppl.push_back(P("Jojo")); // 2 element(s) moved, 1 element added, 3 move(s) in all; size=3, capacity=4

// assume the 4th push_back is performed
ppl.push_back(P("Jojo")); // 0 element(s) moved, 1 element added, 1 move(s) in all; size=4, capacity=4

因此移动构造函数被调用了 6 次。顺便说一句,如果你再执行一次 push_back ,只会调用一次移动构造函数;因为第 4 次 push_back 没有发生重新分配。

您可以使用 std::vector::reserve 来避免重新分配。

vector<P> ppl;
ppl.reserve(3); // prohibit reallocations for the following 3 push_back
ppl.push_back(P("Jojo"));
ppl.push_back(P("Jojo"));
ppl.push_back(P("Jojo"));