4

I'm familiar, that the append in std::string returns std::string& and therefore it do not qualify to be moved from, so the result will not be moved.

#include <string>


int main()
{
    std::string s = std::string("A").append("B");
    return s.size();
}

https://godbolt.org/z/M63aWW

#include <string>


int main()
{
    std::string s = std::move(std::string("A").append("B"));
    return s.size();
}

https://godbolt.org/z/jTnsac

There you can see, that the latter example will produce one fewer allocation and therefore in this case it is better to move something that may looks like a temporary. My question is why they (the committee) do not add simple overload on && to make the result of append either std::string&, or std::string&& depending on the context? I mean something similar to std::optional is doing with value. Is there a example that will prove such optimization bogus?

koscelansky
  • 153
  • 8
  • 1
    Can you post an example where this would actually be useful? auto res = std::string("A").append("B"); dosent really make sense. – Cortex0101 Jul 21 '20 at 09:51
  • @Cortex Yes it doesn't make sense, but when you are trying to concatenate few strings, that may be quite large you want to reallocate as little as possible. And `append` will reuse the buffer, so there will be less allocations overall. – koscelansky Jul 21 '20 at 10:10
  • Workaround: `std::string s = std::move(std::string("A").append("B"));` but big meh to all of it. It's just not a compelling use case. – Asteroids With Wings Jul 21 '20 at 10:49

2 Answers2

7

You can't simply add an && overload. You'd have to make the original function & too. And that's potentially a breaking change.

All that for very little gain. Since append() modifies the source string and returns *this more for chaining rather than assigning the result to anything else, the code you wrote is unidiomatic. If you want that, use +, which is the idiomatic form of building a string for an expression result, and already has the requisite overloads to be efficient:

auto s = "A"s + "B";
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 1
    I have two things on that. Here `"A"s + "B"`, but as the strings get larger and there are more than two strings, this will reallocate the buffer on every single `+`, making it a bit suboptimal. How will the addition of `&` breaks code, when there will also be `&&` overload? I do not get that. – koscelansky Jul 21 '20 at 10:07
  • 2
    @koscelansky Check [overloads 6-12](https://en.cppreference.com/w/cpp/string/basic_string/operator%2B) for `operator+` - they do the moving internally. – Ted Lyngmo Jul 21 '20 at 10:26
7

As is covered in P1165R1, the rules for allocator propagation for basic_string’s operator+ are complex and a root of inconsistencies over different library implementations.

Make stateful allocator propagation more consistent for operator+(basic_string)

[...] Allocator propagation for basic_string’s operator+ is haphazard, inconsistent, and a source of implementation divergence. Let's make them consistent. [...]

P1165R1 has been accepted for C++20.

The append() member function does not have the same semantics, is not as heavily overloaded and does not suffer from the same ”haphazardness ...” as operator+ (prior to P1165R1). There would be no reason for the former to join the domain of the latter; basic_string is already a monster of a container (which is not the case for your counter-example optional, which is not a container in the standardese sense, even if it has semantics similar to a stl container).

dfrib
  • 70,367
  • 12
  • 127
  • 192