Мне просто пришло в голову, что operator+
& Ко может работать на this
для значений; то есть дали класс C
можно сделать это:
class C {
// ...
C operator-( const C& rhs ) const & {
C result = *this;
result -= rhs;
return result;
}
C&& operator-( const C& rhs ) && {
*this -= rhs;
return std::move( *this );
}
};
Это предотвратит копирование, просто изменив временные значения на месте.
Будет ли это работать так, как я ожидал? Это разумная оптимизация или компилятор будет создавать такой же быстрый код?
Допустим, мы просто завернуть std::string
и сделать упрощенную версию operator+
:
struct C {
std::string val;
C&& operator+(const C& rhs) && {
val += rhs.val;
return std::move(*this);
}
std::string::iterator begin() { return val.begin(); }
std::string::iterator end() { return val.end(); }
};
С этим, это прекрасно работает:
for (char c : C{"hello"}) { .. }
Выражение range-for продлит срок жизни временного объекта, так что все в порядке. Однако учтите это:
for (char c : C{"hello"} + C{"goodbye"}) { .. }
Мы эффективно имеем:
auto&& __range = C{"hello"}.operator+(C{"goodbye"});
Здесь мы не привязываем временную ссылку. Мы связываем ссылку. Срок жизни объекта не увеличивается, потому что … это не объект. Таким образом, у нас есть свисающая ссылка и неопределенное поведение. Это было бы очень удивительно для пользователей, которые ожидали бы, что это сработает:
for (char c : std::string{"hello"} + std::string{"goodbye"}) { .. }
Вы должны вернуть значение:
C operator+(const C& rhs) && {
val += rhs.val;
return std::move(*this);
}
Это решает эту проблему (так как теперь у нас есть временное расширение), и если перемещение ваших объектов дешевле, чем их копирование, это победа.