This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 2968. Inconsistencies between `basic_string reserve` and `vector/unordered_map/unordered_set reserve` functions

Section: 23.4.3.5 [string.capacity] Status: Resolved Submitter: Andrew Luo Opened: 2017-05-30 Last modified: 2020-09-06

Priority: 3

View all other issues in [string.capacity].

View all issues with Resolved status.

Discussion:

According to 23.4.3.5 [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 24.3.11.3 [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 23.4.3.5 [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.

[2017-07 Toronto Monday issue prioritization]

Priority 3; status to LEWG

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

Proposed resolution:

This wording is relative to N4659.

1. Edit 23.4.3.5 [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()`.