将项目附加到矢量会复制所有以前的项目

时间:2016-01-09 13:37:56

标签: c++ c++11 vector push-back

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

情况似乎如此。但是,每次我附加到向量时,所有先前的项目都会被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并不能解决这个问题,并增加了额外的动作。

2 个答案:

答案 0 :(得分:4)

Vector会在存储空间不足时重新分配内存块,并将旧对象复制到新位置。您可以通过致电vector.reserve(<expected number of items>);来大幅减少此类重新分配的次数 另外值得注意的是,向量保证了摊销常数push_back的复杂性。这意味着当您不断添加项目时,重新分配的次数会越来越少,因此通常不会引起关注。

或者,如果您只需要某种容器并且不需要将其连续分配到内存中,请考虑使用其他容器。与std::deque一样。

答案 1 :(得分:3)

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

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