Целесообразно ли перегружать операторы с помощью ref-квалификатора, чтобы предотвратить временные задержки?

Мне просто пришло в голову, что 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 );
}
};

Это предотвратит копирование, просто изменив временные значения на месте.

Будет ли это работать так, как я ожидал? Это разумная оптимизация или компилятор будет создавать такой же быстрый код?

6

Решение

Допустим, мы просто завернуть 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);
}

Это решает эту проблему (так как теперь у нас есть временное расширение), и если перемещение ваших объектов дешевле, чем их копирование, это победа.

5

Другие решения


По вопросам рекламы [email protected]