Да и нет.
оператор + =
Семантика перемещения не всегда полезна для operator+=
в целом, потому что вы уже модифицируете левый аргумент (this
), поэтому у вас уже есть ресурсы для работы в большинстве случаев.
Тем не менее, как оптимизация, это может стоить того. Представьте себе реализацию std::string
, конструктор по умолчанию которой не выделяет никакой памяти. Тогда std::string::operator+=(std::string&&)
может просто украсть ресурсы у RHS. Или представьте, что буфер RHS достаточно большой, чтобы вместить все, а LHS - нет, тогда, если вы можете использовать буфер RHS, то у вас все в порядке: просто поменяйте местами и добавьте.
Итак, это может стоить того, но вы должны изучить это. Поэтому:
T& T::operator+=(T const&)
: всегда присутствует
T& T::operator+=(T&&)
: включить семантику перемещения, когда это имеет смысл
оператор +
Здесь это всегда полезно (при условии, что мы говорим о классах, для которых полезна семантика перемещения).
Дело в том, что operator+
создает временное (неожиданно), поэтому обычно для этого временного необходимо создать ресурсы . Однако, если он может украсть их, а не создать, это, безусловно, дешевле.
Однако не обязательно указывать все перегрузки:
T operator+(T const&, T const&)
T operator+(T&&, T const&)
T operator+(T const&, T&&)
T operator+(T&&, T&&)
(требуется для устранения неоднозначности)
Нет, вы можете использовать тот же трюк, который используется operator=
, и создать временное право в сигнатуре функции (взяв один аргумент за копию). Если тип является перемещаемым, будет вызван конструктор перемещения, в противном случае это будет конструктор копирования, но так как вам все равно нужен временный объект, без потери производительности.
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(T const& left, T right) { right += left; return right; } // commutative
inline T operator+(T left, T&& right) { left += right; return left; } // disambiguation
Не много выигрыша (3 вместо 4), но я возьму все, что смогу!
Конечно, для строки, operator+
не является коммутативным (вот почему это плохая перегрузка), поэтому для фактической реализации второй перегрузки потребуется prepend
метод.
РЕДАКТИРОВАТЬ : следуя Переместить семантику и перегрузку операторов кажется, что я был немного переосмыслен. Кража из ответа Бена Фойгта, мы получаем:
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(const T& left, T&& right) { right += left; return right; }
С другой стороны, похоже, это работает только для коммутативных операций; -
не работает таким образом, но, вероятно, может быть адаптировано, /
и %
с другой стороны ...