Title
basic_string misuses "Effects: Equivalent to"
Status
resolved
Section
[string.assign]
Submitter
Jonathan Wakely

Created on 2017-02-03.00:00:00 last changed 72 months ago

Messages

Date: 2017-04-22.13:21:41

Proposed resolution:

This wording is relative to N4659.

  1. Change [string.assign] as indicated:

    basic_string& assign(size_type n, charT c);
    

    -22- Effects: Equivalent to assign(basic_string(n, c, get_allocator())).

Date: 2017-03-15.00:00:00

[ 2017-03-07, LWG reflector discussion ]

Thomas and Jonathan remark that LWG 2788 fixed most cases except the allocator respectance and provide wording for this:

Resolved by the adoption of P1148 in San Diego.

Date: 2017-03-15.00:00:00

[ 2017-03-04, Kona ]

Set priority to 3. Thomas to argue on reflector that this is NAD.

Date: 2017-02-03.00:00:00

basic_string::assign(size_type n, charT c); says:

Effects: Equivalent to assign(basic_string(n, c)).

This requires that a new basic_string is constructed, using a default-constructed allocator, potentially allocating memory, and then that new string is copy-assigned to *this, potentially propagating the allocator. This must be done even if this->capacity() > n, because memory allocation and allocator propagation are observable side effects. If the allocator doesn't propagate and isn't equal to this->get_allocator() then a second allocation may be required. This can't be right; it won't even compile if the allocator isn't default constructible.

basic_string::assign(InputIterator first, InputIterator last) has a similar problem, even if the iterators are random access and this->capacity() > distance(first, last).

basic_string::assign(std::initializer_list<charT> doesn't say "Equivalent to" so maybe it's OK to not allocate anything if the list fits in the existing capacity.

basic_string::append(size_type, charT) and basic_string::append(InputIterator, InputIterator) have the same problem, although they don't propagate the allocator, but still require at least one, maybe two allocations.

A partial fix would be to ensure all the temporaries are constructed with get_allocator() so that they don't require default constructible allocators, and so propagation won't alter allocators. The problem of observable side effects is still present (the temporary might need to allocate memory, even if this->capacity() is large) but arguably it's unspecified when construction allocates, to allow for small-string optimisations.

History
Date User Action Args
2018-11-25 18:34:32adminsetstatus: new -> resolved
2017-04-22 13:21:41adminsetmessages: + msg9149
2017-04-22 13:21:41adminsetmessages: + msg9148
2017-03-14 03:14:09adminsetmessages: + msg9113
2017-02-03 00:00:00admincreate