reserve
, shrink_to_fit
, and resize
functionsSection: 23.3.11.3 [vector.capacity], 23.3.5.3 [deque.capacity] Status: C++14 Submitter: Nikolay Ivchenkov Opened: 2011-02-20 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with C++14 status.
Discussion:
I have several questions with regard to the working paper N3225 (C++0x working draft):
Where the working draft specifies preconditions for shrink_to_fit
member function of std::vector
and std::deque
?
Where the working draft specifies preconditions for 'void reserve(size_type n)
'
member function of std::vector
?
Does a call to 'void resize(size_type sz)
' of std::vector
require
the element type to be DefaultConstructible
? If yes, why such
requirement is not listed in the Requires paragraph?
Does a call to 'void resize(size_type sz)
' of std::vector
require
the element type to be MoveAssignable
because the call erase(begin() + sz, end())
mentioned in the Effects paragraph would require the element type to be MoveAssignable
?
Why CopyInsertable
requirement is used for 'void resize(size_type sz)
' of std::vector
instead of MoveInsertable
requirement?
[2011-06-12: Daniel comments and provides wording]
According to my understanding of the mental model of vector (and to some parts for deque) the some requirements are missing in the standard as response to above questions:
shrink_to_fit
for both std::vector
and std::deque
should impose the MoveInsertable
requirements. The reason for this is, that these containers
can host move-only types. For a container type X
the C++03 idiom X(*this).swap(*this)
imposes the CopyInsertable
requirements which would make the function call ill-formed,
which looks like an unacceptable restriction to me. Assuming the committee decides to support the
move-only case, further wording has to be added for the situation where such a move-only type could
throw an exception, because this can leave the object in an unspecified state. This seems consistent
with the requirements of reserve
, which seems like a very similar function to me (for
vector
). And this brings us smoothly to the following bullet:
I agree that we are currently missing to specify the preconditions of the reserve
function.
My interpretation of the mental model of this function is that it should work for move-only types, which
seems to be supported by the wording used in 23.3.11.3 [vector.capacity] p2:
[…] If an exception is thrown other than by the move constructor of a non-CopyInsertable type, there are no effects.
Given this statement, the appropriate requirement is MoveInsertable
into the vector
.
vector::resize(size_type)
misses to list the DefaultConstructible
requirements.
erase
implies the MoveAssignable
requirements. I don't think that this implication is intended. This function requires "append" and
"pop-back" effects, respectively, where the former can be realized in terms of MoveInsertable
requirements. The same fix in regard to using pop_back
instead of erase
is necessary
for the two argument overload of resize
as well (no MoveAssignable
is required).
CopyInsertable
requirement is incorrect and should be MoveInsertable
instead.In addition to above mentioned items, the proposed resolution adds a linear complexity bound for
shrink_to_fit
and attempts to resolve the related issue 2066.
[ 2011 Bloomington ]
Move to Ready.
Note for editor: we do not normally refer to 'linear time' for complexity requirements, but there is agreement that any clean-up of such wording is editorial.
Proposed resolution:
This wording is relative to the FDIS.
Edit 23.3.5.3 [deque.capacity] as indicated [Remark: The suggested change of p4 is
not redundant, because CopyInsertable
is not necessarily a refinement of MoveInsertable
in contrast to the fact that CopyConstructible
is a refinement of MoveConstructible
]:
void resize(size_type sz);-1- Effects: If
-2- Requires:sz <= size()
, equivalent tocallingerase(begin() + sz, end());
pop_back()
size() - sz
times. Ifsize() < sz
, appendssz - size()
value-initialized elements to the sequence.T
shall beMoveInsertable
into*this
andDefaultConstructible
.
void resize(size_type sz, const T& c);-3- Effects: If
sz <= size()
, equivalent to callingpop_back()
size() - sz
times. Ifsize() < sz
, appendssz - size()
copies ofc
to the sequence.if (sz > size()) insert(end(), sz-size(), c); else if (sz < size()) erase(begin()+sz, end()); else ; // do nothing-4- Requires:
T
shall beMoveInsertable
into*this
andCopyInsertable
into*this
.
void shrink_to_fit();-?- Requires:
-?- Complexity: Takes at most linear time in the size of the sequence. -5- Remarks:T
shall beMoveInsertable
into*this
.shrink_to_fit
is a non-binding request to reduce memory use but does not change the size of the sequence. [ Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ]
Edit 23.3.11.3 [vector.capacity] as indicated including edits that also resolve 2066
[Remark: The combined listing of MoveInsertable
and CopyInsertable
before p12 is not redundant,
because CopyInsertable
is not necessarily a refinement of MoveInsertable
in contrast to the
fact that CopyConstructible
is a refinement of MoveConstructible
]:
[…]
void reserve(size_type n);-?- Requires:
-2- Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. AfterT
shall beMoveInsertable
into*this
.reserve()
,capacity()
is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value ofcapacity()
otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument ofreserve()
. If an exception is thrown other than by the move constructor of a non-CopyInsertable
type, there are no effects. -3- Complexity: It does not change the size of the sequence and takes at most linear time in the size of the sequence. -4- Throws:length_error
ifn > max_size()
.[footnote 266] -5- Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. It is guaranteed that no reallocation takes place during insertions that happen after a call toreserve()
until the time when an insertion would make the size of the vector greater than the value ofcapacity()
.
void shrink_to_fit();-?- Requires:
-?- Complexity: Takes at most linear time in the size of the sequence. -6- Remarks:T
shall beMoveInsertable
into*this
.shrink_to_fit
is a non-binding request to reducecapacity()
tosize()
. [ Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] If an exception is thrown other than by the move constructor of a non-CopyInsertable
T
there are no effects.
[…]
void resize(size_type sz);-9- Effects: If
-10- Requires:sz <= size()
, equivalent tocallingerase(begin() + sz, end());
pop_back()
size() - sz
times. Ifsize() < sz
, appendssz - size()
value-initialized elements to the sequence.T
shall beinto
CopyMoveInsertable*this
andDefaultConstructible
. -??- Remarks: If an exception is thrown other than by the move constructor of a non-CopyInsertable
T
there are no effects.
void resize(size_type sz, const T& c);-11- Effects: If
sz <= size()
, equivalent to callingpop_back()
size() - sz
times. Ifsize() < sz
, appendssz - size()
copies ofc
to the sequence.if (sz > size()) insert(end(), sz-size(), c); else if (sz < size()) erase(begin()+sz, end()); else ; // do nothing-??- Requires:
-12-T
shall beMoveInsertable
into*this
andCopyInsertable
into*this
.RequiresRemarks: If an exception is thrown other than by the move constructor of a non-CopyInsertable
T
there are no effects.