RFC: Allow moved-from strings to be non-empty

Jonathan Wakely jwakely@redhat.com
Fri Oct 26 09:55:00 GMT 2018


On 26/10/18 12:16 +0300, Ville Voutilainen wrote:
>On Fri, 26 Oct 2018 at 01:42, Marc Glisse <marc.glisse@inria.fr> wrote:
>>
>> On Fri, 26 Oct 2018, Ville Voutilainen wrote:
>>
>> > I would rather not introduce a behavioral difference between us and
>> > libc++.
>>
>> Why not? There are already several, and it helps find bugs. Maybe you
>> could convince libc++ to change as well if you want to keep the behavior
>> the same?
>
>What bugs?

Assuming the string is empty after a move and appending to it without
calling clear() first.


>> > It does slightly concern me that some users might
>> > actually semantically expect a moved-from string to be empty, even
>> > though that's not guaranteed, although for non-SSO cases
>> > it *is* guaranteed.
>>
>> Is it? In debug mode, I'd be tempted to leave the string as "moved" (size
>> 5, short string so there is no allocation).
>
>Sigh. Apparently it isn't, because the standard doesn't bother placing
>complexity
>requirements on string constructors.

Writing 5 bytes into the SSO buffer would be constant complexity :-P

>Even so, I'd prefer string acting
>like vector,
>so that it will leave the source of a move in an empty state, rather
>than an unspecified
>state.

It's not guaranteed for vector either. An allocator with POCMA==false
doesn't propagate on move assignment and if the source object's
allocator isn't equal to the target's it will copy, and there's no
guarantee the source will be empty.

This would be a conforming change to our vector:

--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -1793,7 +1793,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
            // so we need to individually move each element.
            this->assign(std::__make_move_if_noexcept_iterator(__x.begin()),
                         std::__make_move_if_noexcept_iterator(__x.end()));
-           __x.clear();
          }
       }
 #endif

That might even have a bigger performance benefit, because clearing a
vector runs destructors, it doesn't just set the length and write a
null terminator.

If you're using a vector as a buffer of objects and the first thing
you do after v1=std::move(v2) is v2.resize(n) then it's a
pessimization to have cleared it. 

>Despite the standard not requiring that, it's more useful
>programmatically
>to have the empty state than the unspecified state, especially when the state
>is empty in some cases anyway.



More information about the Libstdc++ mailing list