Улучшает ли безопасность маркировку операторов присваивания только для lvalue?

Если T это тип класса с подписью по умолчанию для оператора присваивания, тогда мы можем написать:

T const &ref = ( T{} = something ); 

который создает висячую ссылку. Однако с подписью:

T &operator=(T t) &

приведенный выше код со свисающей ссылкой не удастся скомпилировать. Это предотвратит некоторые ситуации, когда мы возвращаем lvalue, который обозначает временный объект - нежелательные ситуации, потому что они могут привести к висящим ссылкам.

Есть ли причина не делать этого; Будем ли мы отключать любые допустимые варианты использования для операторов присваивания?

Я думаю, что те же комментарии могут относиться и к составным операторам присваивания, += и т.д. Более реалистичным случаем может быть:

std::string const &s = std::string("Hello, ") += "world!";

где опечатка останется незамеченной до времени выполнения UB.

1 ответ

Решение

По моему опыту, в редком случае вы действительно хотите назначить значение

template<class T>
std::remove_reference_t<T>& as_lvalue(T&&t){return t;}

и делать as_lvalue( tmp() ) = foo вместо tmp()=foo не огромный барьер. Это означает, что случайный кусок кода, который действительно присваивал rvalue, теперь сломается; Я лично подозреваю, что большинство таких случаев на самом деле являются неизученными ошибками.


Ограничение каждого типа в std быть ограниченным по значению operator= был рассмотрен во время стандартизации C++11 во Франкфурте (2009/07). Обоснование решения, записанное в протоколе:

N2819, "N2819 Ref-Qualifiers для операторов присваивания Стандартной библиотеки" первоначально рассматривался LWG. Это предложение было направлено на изменение 350 операторов копирования в стандартной библиотеке C++, чтобы предотвратить операции присваивания, в которых левый операнд является r-значением. Из-за большого количества необходимых изменений предложение было отправлено в EWG с просьбой пересмотреть поведение по умолчанию для неявных операторов копирования-назначения, чтобы присвоение r-значению не разрешалось. EWG решила сохранить статус-кво из-за опасений по поводу обратной совместимости.

Я прочитал это как "350 изменений? Как насчет смены языка?". EWG сказала: "Нет, это изменение языка может нарушить совместимость". И, возможно, предложение умерло на корню.

В 2009 году C++11 (тогда C++0x) уже отставал от графика. Поскольку предложение включало 300 изменений в библиотеку, которые (в теории) могли вызвать регрессии. Никакая другая причина не была приведена в протоколе. Отказ от того, что он не стоит боли регрессий (или даже проверки частоты регрессий!), Понятен. Так что я бы не предполагал предубеждения по поводу идеи только потому, что C++ отверг ее std,

Другие вопросы по тегам