C++ 在 std::vector 中调整大小与 push_back :它是否避免了不必要的复制分配?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1902832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
resize versus push_back in std::vector : does it avoid an unnecessary copy assignment?
提问by Chuim
When invoking the method push_back
from std::vector
, its size is incremented by one, implying in the creation of a new instance, and then the parameter you pass will be copied into this recently created element, right? Example:
push_back
从调用方法时std::vector
,它的大小增加一,意味着创建一个新实例,然后你传递的参数将被复制到这个最近创建的元素中,对吗?例子:
myVector.push_back(MyVectorElement());
Well then, if I want to increase the size of the vector with an element simply using its default values, wouldn't it be better to use the resize
method instead? I mean like this:
那么,如果我想简单地使用其默认值来增加带有元素的向量的大小,那么使用该resize
方法不是更好吗?我的意思是这样的:
myVector.resize(myVector.size() + 1);
As far as I can see, this would accomplish exactly the same thing but would avoid the totally unnecessary assignment copy of the attributes of the element.
据我所知,这将完成完全相同的事情,但会避免元素属性的完全不必要的赋值副本。
Is this reasoning correct or am I missing something?
这个推理是正确的还是我遗漏了什么?
采纳答案by Yacoby
At least with GCC, it doesn't matter which you use (Results below). However, if you get to the point where you are having to worry about it, you should be using pointers or (even better) some form of smart pointers.. I would of course recommend the ones in the boost library.
至少对于 GCC,您使用哪个并不重要(结果如下)。但是,如果您到了不得不担心的地步,您应该使用指针或(甚至更好)某种形式的智能指针。. 我当然会推荐boost 库中的那些。
If you wanted to know which was better to use in practice, I would suggest either push_back
or reserve
as resize will resize the vector every time it is called unless it is the same size as the requested size. push_back
and reserve will only resize the vector if needed. This is a good thing as if you want to resize the vector to size+1
, it may already be at size+20
, so calling resize would not provide any benefit.
如果你想知道这是更好地在实践中使用,我建议要么push_back
或reserve
作为调整大小每次调用,除非它的大小与所要求的大小同时将调整向量。push_back
并且保留只会在需要时调整向量的大小。这是一件好事,因为如果您想将向量调整为size+1
,它可能已经在size+20
,因此调用 resize 不会提供任何好处。
Test Code
测试代码
#include <iostream>
#include <vector>
class Elem{
public:
Elem(){
std::cout << "Construct\n";
}
Elem(const Elem& e){
std::cout << "Copy\n";
}
~Elem(){
std::cout << "Destruct\n";
}
};
int main(int argc, char* argv[]){
{
std::cout << "1\n";
std::vector<Elem> v;
v.push_back(Elem());
}
{
std::cout << "\n2\n";
std::vector<Elem> v;
v.resize(v.size()+1);
}
}
Test Output
测试输出
1
Construct
Copy
Destruct
Destruct
2
Construct
Copy
Destruct
Destruct
回答by GManNickG
I find myVector.push_back(MyVectorElement());
much more direct and easier to read.
我发现myVector.push_back(MyVectorElement());
更直接,更容易阅读。
The thing is, resize
doesn't just resize the array and default-construct elements on those places; that's just what it defaults to. It actually takes a second parameter which is what each new element will be made a copy of, and this defaults to T()
. In essence, your two code samples are exactlythe same.
问题是,resize
不只是在这些地方调整数组和默认构造元素的大小;这就是它的默认设置。它实际上需要第二个参数,即每个新元素将复制的内容,默认为T()
. 本质上,您的两个代码示例完全相同。
回答by rafak
A c++0x perspective concerning test code of Yacobi's accepted answer:
关于 Yacobi 接受的答案的测试代码的 c++0x 观点:
Add a moveconstructor to the class:
Elem(Elem&& e) { std::cout << "Move\n"; }
With gcc I get "Move" instead of "Copy" as output for
push_back
, which is far more efficient in general.Even slightly better with emplaceoperations (take the same arguments as the constructor):
v.emplace_back()
向类添加移动构造函数:
Elem(Elem&& e) { std::cout << "Move\n"; }
使用 gcc 我得到“移动”而不是“复制”作为输出
push_back
,这通常效率更高。使用emplace操作甚至稍微好一点 (采用与构造函数相同的参数):
v.emplace_back()
Test Output:
测试输出:
1
Construct
Destruct
2
Construct
Copy
Destruct
Destruct
回答by Andreas Brinck
回答by Martin York
When you do push_back() the method checks the underlying storage area to see if space is needed. If space is needed then it will allocate a new contiguous area for all elements and copy the data to the new area.
当您执行 push_back() 时,该方法会检查底层存储区域以查看是否需要空间。如果需要空间,那么它将为所有元素分配一个新的连续区域并将数据复制到新区域。
BUT: The size of the newly allocated space is not just one element bigger. It uses a nifty little algorithm for increasing space (I don't think the algorithm is defined as part of the standard but it usually doubles the allocated space). Thus if you push a large number of elements only a small percentage of them actually cause the underlying space to be re-allocated.
但是:新分配的空间的大小不仅仅是大一个元素。它使用一个漂亮的小算法来增加空间(我不认为该算法被定义为标准的一部分,但它通常会将分配的空间加倍)。因此,如果您推送大量元素,只有其中一小部分元素实际上会导致底层空间被重新分配。
To actually increase the allocate space manually you have two options:
要实际手动增加分配空间,您有两个选择:
reserve()
This increases the underlying storage space without adding elements to the vector. Thus making it less likely that future
push_back()
calls will require the need to increase the space.resize()
This actually adds/removes elements to the vector to make it the correct size.
capacity()
Is the total number of elements that can be stored before the underlying storage needs to be re-allocated. Thus if
capacity() > size()
a push_back will not cause the vector storage to be reallocated.
reserve()
这增加了底层存储空间,而无需向向量添加元素。从而降低未来
push_back()
调用需要增加空间的可能性。resize()
这实际上是向向量添加/删除元素以使其具有正确的大小。
capacity()
是在底层存储需要重新分配之前可以存储的元素总数。因此,如果
capacity() > size()
push_back 不会导致重新分配向量存储。
回答by CB Bailey
You are right that push_back
cannot avoid at least one copy but I think that you are worrying about the wrong things, but resize
will not necessarily perform any better either (it copies the value of its second parameter which defaults to a default constructed temporary anyway).
您是对的,push_back
无法避免至少一个副本,但我认为您担心的是错误的事情,但resize
也不一定表现得更好(它复制了其第二个参数的值,该参数默认为默认构造的临时值)。
vector
is not the right container for objects which are expensive to copy. (Almost) any push_back
or resize
could potentially cause every current member of the vector
to be copied as well as any new member.
vector
不是复制昂贵对象的正确容器。(几乎)任何push_back
或resize
可能导致vector
复制的每个当前成员以及任何新成员。
回答by Drakosha
myVector.resize(myVector.size() + 1);
will call an empty constructor of MyVectorElement. What are you trying to accomplish? In order to reserve space in a vector (and save memory allocation overhead) there's reserve() method. You cannot avoid the constructor.
将调用 MyVectorElement 的空构造函数。你想达到什么目的?为了在向量中保留空间(并节省内存分配开销),有reserve() 方法。您无法避免构造函数。
回答by Tim Sylvester
When you call push_back
, assuming that no resizing of the underlying storage is needed, the vector
class will use the "placement new" operator to copy-construct the new elements in-place. The elements in the vector will notbe default-constructed before being copy-constructed.
当您调用 时push_back
,假设不需要调整底层存储的大小,vector
该类将使用“placement new”运算符就地复制构造新元素。向量中的元素在被复制构造之前不会被默认构造。
When you call resize
, almost the exact same sequence occurs. vector
allocates storage and then copies the default value via placement new into each new location.
当您调用 时resize
,会发生几乎完全相同的序列。 vector
分配存储,然后通过放置 new 将默认值复制到每个新位置。
The construction looks like this:
结构如下所示:
::new (p) _T1(_Val);
Where p
is the pointer to the vector storage, _T1
is the type being stored in the vector, and _Val
is the "default value" parameter (which defaults to _T1()
).
哪里p
是指向向量存储的指针,_T1
是存储在向量中的类型,_Val
是“默认值”参数(默认为_T1()
)。
In short, resize and push_back do the same things under the covers, and the speed difference would be due to multiple internal allocations, multiple array bounds checks and function call overhead. The time and memory complexity would be the same.
简而言之,resize 和 push_back 在幕后做同样的事情,速度差异是由于多次内部分配、多次数组边界检查和函数调用开销。时间和内存复杂度是一样的。
回答by Matt
Obviously you're worried about efficiency and performance.
显然,您担心效率和性能。
std::vector is actually a very good performer. Use the reserve method to preallocate space if you know roughly how big it might get. Obviously this is at the expense of potentially wasted memory, but it can have quite a performance impact if you're using push_back a lot.
std::vector 实际上是一个非常好的表现者。如果您大致知道空间可能有多大,请使用保留方法来预分配空间。显然,这是以潜在的内存浪费为代价的,但是如果您经常使用 push_back,它会对性能产生相当大的影响。
I believe it's implementation dependent as to how much memory is reserved up front for a vector if any at all, or how much is reserved for future use as elements are added. Worst case scenario is what you're stating - only growing by one element at a time.
我相信它的实现取决于为向量预留了多少内存(如果有的话),或者在添加元素时预留了多少供将来使用。最坏的情况就是你所说的 - 一次只增长一个元素。
Try some performance testing in your app by comparing without the reserve and with it.
通过在没有保留和有保留的情况下进行比较,在您的应用中尝试一些性能测试。
回答by DaMacc
push_back: you create the object and it gets copied in the vector.
resize: the vector creates the object with the default constructor and copies it in the vector.
push_back:您创建对象并将其复制到向量中。
resize:向量使用默认构造函数创建对象并将其复制到向量中。
Speed difference: You will have to test your implementation of the STL and your compiler, but I think it won't matter.
速度差异:您必须测试 STL 的实现和编译器,但我认为这无关紧要。