#cpp #cpp11 #оператор_присваивания
Итак имеется два оператора присваивания - копирующий и перемещающий, например такие: Implementation& operator= (const Implementation & other) noexcept; Implementation& operator= ( Implementation && other) noexcept; При этом в данном вопросе (в первом ответе) говорится, что есть определенные преимущества объявления оператора = следующим образом, т.е. по значению: Implementation& operator= ( Implementation other) noexcept; Т.е. в таком случае мы можем не объявлять оператор, принимающий &&? Иначе просто возникнет неопределенность. Почему же тогда в стандартной библиотеке используется первая техника, а в бусте можно найти такое: #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES template < typename ValueType > any& operator= (const ValueType& rhs) { any(rhs).swap(*this); return *this; } any& operator= (any rhs) { any(rhs).swap(*this); return *this; } #else any& operator= (const any& rhs) { any(rhs).swap(*this); return *this; } any& operator= (any&& rhs) BOOST_NOEXCEPT { rhs.swap(*this); any().swap(rhs); return *this; } #endif Почему не сделать во втором блоке препроцессора ту же реализацию: any& operator= (any rhs) { any(rhs).swap(*this); return *this; } Или это сделано для того, чтобы в операторе =, принимающем && сделать обнуление rvalue значения?
Ответы
Ответ 1
Почему не сделать во втором блоке препроцессора ту же реализацию: any& operator= (any rhs) { any(rhs).swap(*this); return *this; } Дело в том, что с приходом C++11 и появлением семантики перемещения появилась возможность разделить ситуации, когда нам действительно нужна новая копия объекта и ситуации, когда мы хотим только переместить один объект в другой. При таком разделении копирующий оператор присваивания (или конструктор) может бросать исключения, а перемещающий оператор практически всегда можно реализовать без бросания исключений и без необходимости создавать временные объекты. Соответственно с переходом на С++11 приведенный конструктор получится неоптимальным так как 1) он может кидать исключения 2) он всегда создает временный объект. Пример сценария с оверхедом: any first{}; any second{}; first = ::std::move(second); // создаем еще и третий объект - аргумент оператора Использовать copy-and-swap оператор присваивания совместно с перемещающим оператором присваивания не получится, так как в этом случае при присваивании rvalue reference компилятор не сможет выбрать между ними.
Комментариев нет:
Отправить комментарий