Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why has the std::vector::resize signature been changed in C++11?

What are the reasons behind the change in std::vector::resize from the pre-C++11:

void resize( size_type count, T value = T() ); 

to the compatible C++11 form:

void resize( size_type count ); void resize( size_type count, const value_type& value); 
like image 340
Martin Avatar asked Jun 08 '13 18:06

Martin


People also ask

How do I resize the size of a vector in C++?

C++ Vector Library - resize() Function The C++ function std::vector::resize() changes the size of vector. If n is smaller than current size then extra elements are destroyed. If n is greater than current container size then new elements are inserted at the end of vector.

What does std :: vector resize do?

vector::resizeResizes the container to contain count elements. If the current size is greater than count , the container is reduced to its first count elements.

Can vector be resized?

Vectors are known as dynamic arrays which can change its size automatically when an element is inserted or deleted. This storage is maintained by container.

Does resizing a vector delete data?

Resizing a vector doesn't destroy the values stored in the vector (except for those beyond the new size when shrinking, of course), however growing a vector beyond its capacity will copy (or, in C++11, move) them to a new place, thus invalidating and iterators, pointers or references to those elements.


2 Answers

Paragraph C.2.12 of the Annex C (Compatibility) to the C++11 Standard specifies:

Change: Signature changes: resize

Rationale: Performance, compatibility with move semantics.

Effect on original feature: For vector, deque, and list the fill value passed to resize is now passed by reference instead of by value, and an additional overload of resize has been added. Valid C++ 2003 code that uses this function may fail to compile with this International Standard.

The old resize() function was copy-constructing new elements from value. This makes it impossible to use resize() when the elements of the vector are default-constructible but non-copyable (you may want to move-assign them later on). This explains the "Compatibility with move semantics" rationale.

Moreover, it may be slow if you do not want any copy to occur, just new elements to be default-constructed. Also, the value parameter is passed by value in the C++03 version, which incurs in the overhead of an unnecessary copy (as mentioned by TemplateRex in his answer). This explains the "Performance" rationale.

like image 160
Andy Prowl Avatar answered Oct 01 '22 16:10

Andy Prowl


One reason is that default arguments are always passed, i.e. copied in this case. Doing

 my_vector.resize(1000000)  

would copy 1 million T objects.

In C++11 you now have a choice between copying a user-provided value or default-inserting (i.e. constructing) elements in-place, using the std::allocator_traits<Alloc>::construct() function. This allows resizing of vector with elements that are CopyInsertable but not Copyable.

Note that this change has been done to all sequence containers having a resize() member (vector, deque, forward_list and list), but not for std::string which didn't have a default value argument to begin with.

Update: apart from the Annex to the current Standard cited by @AndyProwl, the original defect report by @HowardHinnant also clarifies:

The problem with passing T by value is that it can be significantly more expensive than passing by reference. The converse is also true, however when it is true it is usually far less dramatic (e.g. for scalar types).

Even with move semantics available, passing this parameter by value can be expensive. Consider for example vector>:

std::vector<int> x(1000); std::vector<std::vector<int>> v; ... v.resize(v.size()+1, x);  

In the pass-by-value case, x is copied once to the parameter of resize. And then internally, since the code can not know at compile time by how much resize is growing the vector, x is usually copied (not moved) a second time from resize's parameter into its proper place within the vector.

With pass-by-const-reference, the x in the above example need be copied only once. In this case, x has an expensive copy constructor and so any copies that can be saved represents a significant savings.

If we can be efficient for push_back, we should be efficient for resize as well. The resize taking a reference parameter has been coded and shipped in the CodeWarrior library with no reports of problems which I am aware of.

like image 23
TemplateRex Avatar answered Oct 01 '22 15:10

TemplateRex