1138. Unusual return value for operator+

Section: 27.4.4.1 [string.op.plus] Status: C++11 Submitter: Alisdair Meredith Opened: 2009-06-12 Last modified: 2021-06-06

Priority: Not Prioritized

View all issues with C++11 status.

Discussion:

Many of the basic_string operator+ overloads return an rvalue-reference. Is that really intended?

I'm considering it might be a mild performance tweak to avoid making un-necessary copies of a cheaply movable type, but it opens risk to dangling references in code like:

auto && s = string{"x"} + string{y};

and I'm not sure about:

auto s = string{"x"} + string{y};

[ 2009-10-11 Howard updated Returns: clause for each of these. ]

[ 2009-11-05 Howard adds: ]

Moved to Tentatively Ready after 5 positive votes on c++std-lib.

Proposed resolution:

Strike the && from the return type in the following function signatures:

27.4 [string.classes] p2 Header Synopsis

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              const basic_string<charT,traits,Allocator>& rhs);

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(const basic_string<charT,traits,Allocator>& lhs,
              basic_string<charT,traits,Allocator>&& rhs);

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              basic_string<charT,traits,Allocator>&& rhs);


template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(const charT* lhs,
              basic_string<charT,traits,Allocator>&& rhs);

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(charT lhs, basic_string<charT,traits,Allocator>&& rhs);

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              const charT* rhs);

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs, charT rhs);

[string.op+]

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              const basic_string<charT,traits,Allocator>& rhs);

Returns: std::move(lhs.append(rhs))

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(const basic_string<charT,traits,Allocator>& lhs,
              basic_string<charT,traits,Allocator>&& rhs);

Returns: std::move(rhs.insert(0, lhs))

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              basic_string<charT,traits,Allocator>&& rhs);

Returns: std::move(lhs.append(rhs)) [Note: Or equivalently std::move(rhs.insert(0, lhs))end note]

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(const charT* lhs,
              basic_string<charT,traits,Allocator>&& rhs);

Returns: std::move(rhs.insert(0, lhs)).

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(charT lhs, basic_string<charT,traits,Allocator>&& rhs);

Returns: std::move(rhs.insert(0, 1, lhs)).

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs,
              const charT* rhs);

Returns: std::move(lhs.append(rhs)).

template<class charT, class traits, class Allocator>
  basic_string<charT,traits,Allocator>&&
    operator+(basic_string<charT,traits,Allocator>&& lhs, charT rhs);

Returns: std::move(lhs.append(1, rhs)).