Title
Inconsistencies between basic_string reserve and vector/unordered_map/unordered_set reserve functions
Status
resolved
Section
[string.capacity]
Submitter
Andrew Luo

Created on 2017-05-30.00:00:00 last changed 74 months ago

Messages

Date: 2018-03-18.23:10:06

Proposed resolution:

This wording is relative to N4659.

  1. Edit [string.capacity] as indicated:

    void reserve(size_type res_arg=0);
    

    -10- The member function reserve() is a directive that informs a basic_string object of a planned change in size, so that it can manage the storage allocation accordingly.

    -11- Effects: After reserve(), capacity() is greater or equal to the argument of reserve, if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). [Note: Calling reserve() with a res_arg argument less than capacity() is in effect a non-binding shrink request. A call with res_arg <= size() is in effect a non-binding shrink-to-fit request. — end note]

    -12- Throws: length_error if res_arg > max_size().

Date: 2018-03-17.00:00:00

[ 2018-3-17 Resolved by P0966, which was adopted in Jacksonville. ]

Date: 2017-07-12.01:30:31

[ 2017-07 Toronto Monday issue prioritization ]

Priority 3; status to LEWG

Date: 2017-05-30.00:00:00

According to [string.capacity] paragraph 11:

-11- Effects: After reserve(), capacity() is greater or equal to the argument of reserve. [Note: Calling reserve() with a res_arg argument less than capacity() is in effect a non-binding shrink request. A call with res_arg <= size() is in effect a non-binding shrink-to-fit request. — end note]

A call to basic_string's reserve function with res_arg <= size() is taken as a non-binding request to shrink the capacity, whereas for vector (and similarly for unordered_map and unordered_set) according to [vector.capacity] p3:

-3- Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). If an exception is thrown other than by the move constructor of a non-CopyInsertable type, there are no effects.

The problem here is that the different behavior makes it that writing template code where the template argument type is a container type (for example std::string or std::vector<char>) calls to reserve can have different meaning depending on which container type the template is instantiated with. It might be a minor issue but it would be nice to fix the inconsistency. I ran into an issue around this when I was porting code from MSVC++ to G++ (For basic_string, MSVC++'s STL implementation, based on Dinkumware, ignores the call if res_arg < capacity() whereas GCC's STL implementation, libstdc++ will actually shrink the string. For the code I wrote this caused a huge performance issue since we were reallocating the entire string with every call to reserve. Of course we could have worked around it by doing the res_arg < capacity() check ourselves, but I think this inconsistency in the standard isn't desirable).

My proposal is to change [string.capacity] paragraph 11 to read:

-11- Effects: After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve().

I realize that this causes the basic_string::reserve to no longer have the secondary property of shrinking, but this is what shrink_to_fit is for.

History
Date User Action Args
2018-03-18 23:10:06adminsetmessages: + msg9758
2018-03-18 23:10:06adminsetstatus: lewg -> resolved
2017-07-12 01:30:31adminsetmessages: + msg9335
2017-07-12 01:30:31adminsetstatus: new -> lewg
2017-06-10 20:15:13adminsetmessages: + msg9236
2017-05-30 00:00:00admincreate