将项目附加到向量会复制所有先前的项目

Appending an item to a vector copies all previous items

在下面的代码中,我希望永远不会调用 A 的复制构造函数,因为项目应该直接在带有 emplace_back 的向量上创建,然后总结果应该是return-价值优化。

好像是这样的。但是,每次我追加到矢量时,所有以前的项目都会作为 emplace_back 调用的结果被复制。为什么会这样?

#include <iostream>
#include <vector>
#include <string>

using namespace std;


static int _id = 0;

class A{
public:
    A(): name(_id++){
        cout << "Created" << this->name << endl;
    }

    A(const A& other): name(other.name){
        cout << "Copied" << this->name << endl;
    }

    A(const A&& other): name(other.name){
        cout << "Moved" << this->name << endl;
    }

    ~A(){
        cout << "Deleted"<< this->name <<endl;
    }

private:
    int name;
};


vector<A>  f2(){
    cout << "Entering f2" << endl;
    auto ret = vector<A>();
    for (int i = 0; i < 3; i++){
        //auto obj = A();
        cout << "Adding obj" << endl;
        ret.emplace_back();
        cout << "Added obj" << endl;
    }
    cout << "Returning" << endl;
    return ret;
}

int main()
{
    {
        auto c = f2();
        cout << "Exiting stack" << endl;
    }
    return 0;
}

我使用 gcc 4.8.4 编译它,使用以下任何一个:

gcc main.cpp -std=c++11
gcc main.cpp -std=c++11 -O3

输出为:

Entering f2
Adding obj
Created0
Added obj
Adding obj
Created1
Copied0
Deleted0
Added obj
Adding obj
Created2
Copied0
Copied1
Deleted0
Deleted1
Added obj
Returning
Exiting stack
Deleted0
Deleted1
Deleted2

而且我希望没有副本,例如:

Entering f2
Adding obj
Created0
Added obj
Adding obj
Created1
Added obj
Adding obj
Created2
Added obj
Returning
Exiting stack
Deleted0
Deleted1
Deleted2

emplace_back 更改为 push_back 并不能解决这个问题,并且会添加额外的动作。

Vector 将 re-allocate 它的内存块,当它用完存储 space 时,并将旧对象复制到它们的新位置。您可以通过调用 vector.reserve(<expected number of items>);
显着减少此类 re-allocations 的数量 同样值得注意的是 vector 保证了摊销常数 push_back 的复杂性。这意味着随着您不断添加项目,重新分配的频率会越来越低,因此通常无需担心。

或者,如果您只需要某种容器而不需要在内存中连续分配它,请考虑使用其他容器。喜欢 std::deque.

此外,如果您将移动构造函数标记为 noexcept,那么当向量增长时,它将移动而不是复制。

另见 How to enforce move semantics when a vector grows?