Функция C ++ 11 std::move(x)
вообще ничего не перемещает. Это просто приведение к значению r. Почему это было сделано? Разве это не заблуждение?
c++
c++11
move-semantics
rvalue-reference
c++-faq
Говард Хиннант
источник
источник
std::move
самом делеstd::char_traits::move
:-)std::remove()
что не удаляет элементы: вам все равно нужно вызвать,erase()
чтобы удалить эти элементы из контейнера. Такmove
что не двигается,remove
не удаляется. Я бы выбрал названиеmark_movable()
дляmove
.mark_movable()
тоже запутался . Это предполагает наличие длительного побочного эффекта, которого на самом деле нет.Ответы:
Верно , что
std::move(x)
это просто приведение к rvalue - точнее к xvalue , а не к prvalue . Верно и то, что наличие названного актерского составаmove
иногда сбивает людей с толку. Однако цель этого наименования - не запутать, а скорее сделать ваш код более читабельным.История компании
move
восходит к первоначальному предложению о переезде в 2002 году . В этой статье сначала представлена ссылка на rvalue, а затем показано, как написать более эффективныйstd::swap
:Следует напомнить, что на данном этапе истории единственное, что
&&
могло означать «», было логическим и . Никто не был знаком ни со ссылками на rvalue, ни с последствиями приведения lvalue к rvalue (без создания копии, как этоstatic_cast<T>(t)
было бы). Поэтому читатели этого кода, естественно, подумают:Также обратите внимание, что
swap
на самом деле это просто замена для всех видов алгоритмов изменения перестановок. Это обсуждение намного больше, чемswap
.Затем предложение вводит синтаксический сахар, который заменяет на
static_cast<T&&>
что-то более читаемое, которое передает не точное, что , а, скорее, почему :Т.е.
move
это просто синтаксический сахар дляstatic_cast<T&&>
, и теперь код довольно наводит на размышления о том, зачем нужны эти приведения: чтобы включить семантику перемещения!Следует понимать, что в контексте истории немногие люди в этот момент действительно понимали тесную связь между rvalue и семантикой перемещения (хотя в статье это также пытается объяснить):
Если бы в то время
swap
было представлено так:Тогда люди бы посмотрели на это и сказали:
Главный момент:
Как было, используя
move
, ни разу никто не спросил:Шли годы, и предложение было уточнено, и понятия lvalue и rvalue были преобразованы в категории значений, которые мы имеем сегодня:
(изображение бессовестно украдены из dirkgently )
Итак, сегодня, если бы мы хотели
swap
точно сказать, что он делает, а не почему , это должно быть больше похоже на:И вопрос, который каждый должен задать себе, заключается в том, является ли приведенный выше код более или менее читаемым, чем:
Или даже оригинал:
В любом случае, опытный программист на C ++ должен знать, что под капотом
move
не происходит ничего, кроме приведения типов . И начинающий программист на C ++, по крайней мереmove
, будет проинформирован о том, что намерение состоит в том, чтобы перейти от правого, а не копировать с правого, даже если они не понимают, как именно это достигается.Вдобавок, если программист желает использовать эту функциональность под другим именем, он не
std::move
обладает монополией на эту функциональность, и в ее реализации не участвует непереносимая языковая магия. Например, если кто-то хочет кодироватьset_value_category_to_xvalue
и использовать его вместо этого, это тривиально:В C ++ 14 он стал еще более кратким:
Так что, если вы так склонны, украсьте
static_cast<T&&>
себя так, как считаете лучше, и, возможно, вы в конечном итоге разработаете новую передовую практику (C ++ постоянно развивается).Так что же
move
делать с точки зрения сгенерированного объектного кода?Учтите это
test
:Скомпилировано с
clang++ -std=c++14 test.cpp -O3 -S
, это создает этот объектный код:Теперь, если тест изменить на:
В объектном коде нет абсолютно никаких изменений . Этот результат можно обобщить на: Для тривиально подвижных объектов
std::move
не оказывает никакого влияния.Теперь давайте посмотрим на этот пример:
Это генерирует:
При запуске
__ZN1XaSERKS_
черезc++filt
это производит:X::operator=(X const&)
. Здесь нет ничего удивительного. Теперь, если тест изменить на:Тогда в сгенерированном объектном коде по- прежнему нет никаких изменений .
std::move
ничего не сделал, кроме приведенияj
к rvalue, а затем это rvalueX
привязывается к оператору присваивания копииX
.Теперь давайте добавим оператор присваивания перемещения к
X
:Теперь объектный код действительно меняется:
Запуск
__ZN1XaSEOS_
черезc++filt
показывает , чтоX::operator=(X&&)
вызывается вместоX::operator=(X const&)
.И это все, что нужно
std::move
! Он полностью исчезает во время выполнения. Его единственное влияние - во время компиляции, когда он может изменить вызываемую перегрузку.источник
digraph D { glvalue -> { lvalue; xvalue } rvalue -> { xvalue; prvalue } expression -> { glvalue; rvalue } }
для всеобщего блага :) Загрузите его здесь как SVGallow_move
;)movable
.std::move
вrvalue_cast
: youtube.com/…rvalue_cast
неоднозначно: какое rvalue оно возвращает?xvalue_cast
было бы последовательным именем здесь. К сожалению, большинство людей в настоящее время также не понимают, что он делает. Надеюсь, что через несколько лет мое утверждение станет ложным.Позвольте мне просто оставить здесь цитату из часто задаваемых вопросов по C ++ 11, написанную Б. Страуструпом, которая является прямым ответом на вопрос OP:
Кстати, FAQ мне очень понравился - его стоит прочитать.
источник