将项目附加到向量会复制所有先前的项目
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?
在下面的代码中,我希望永远不会调用 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?