В C ++ 11 мы можем написать такой код:
struct Cat {
Cat(){}
};
const Cat cat;
std::move(cat); //this is valid in C++11
когда я звоню std::move
, это означает, что я хочу переместить объект, т.е. я изменю объект. Перемещать const
объект нецелесообразно, так почему бы std::move
не ограничить такое поведение? В будущем это будет ловушка, верно?
Здесь ловушка означает, как Брэндон упомянул в комментарии:
«Я думаю, он имел в виду, что это« ловушка »его подлый подлый, потому что, если он не осознает, он заканчивает с копией, которая не то, что он намеревался».
В книге Скотта Мейерса «Эффективный современный C ++» он приводит пример:
class Annotation {
public:
explicit Annotation(const std::string text)
: value(std::move(text)) //here we want to call string(string&&),
//but because text is const,
//the return type of std::move(text) is const std::string&&
//so we actually called string(const string&)
//it is a bug which is very hard to find out
private:
std::string value;
};
Если бы std::move
было запрещено работать с const
объектом, мы могли бы легко обнаружить ошибку, верно?
std::move
сам по себе ничего не делает с объектом. Можно поспоритьstd::move
, плохо назван.CAT cat2 = std::move(cat);
, предполагая, чтоCAT
поддерживает регулярное присвоение перемещений.std::move
это всего лишь гипс, он на самом деле ничего не двигаетОтветы:
здесь мы видим использование
std::move
файлаT const
. Он возвращаетT const&&
. У нас есть конструктор перемещения,strange
который принимает именно этот тип.И это называется.
Это правда, что этот странный тип встречается реже, чем ошибки, которые ваше предложение исправит.
Но, с другой стороны, существующий
std::move
лучше работает в общем коде, где вы не знаете, с каким типом вы работаете: aT
илиT const
.источник
std::move
наconst
объекте.const T&&
. Это выражает «протокол API» типа «я возьму rvalue-ref, но обещаю, что не буду его изменять». Думаю, если не считать использования mutable, это необычно. Возможно, еще один вариант использования - иметь возможность использоватьforward_as_tuple
практически все, а затем использовать это.Вы упускаете из виду одну хитрость, а именно, что на
std::move(cat)
самом деле ничего не движется . Он просто говорит компилятору попытаться переместиться. Однако, поскольку в вашем классе нет конструктора, который принимает aconst CAT&&
, вместо этого он будет использовать неявныйconst CAT&
конструктор копирования и безопасно копировать. Ни опасности, ни ловушки. Если конструктор копирования по какой-либо причине отключен, вы получите ошибку компилятора.печатает
COPY
, нетMOVE
.http://coliru.stacked-crooked.com/a/0dff72133dbf9d1f
Обратите внимание, что ошибка в указанном вами коде связана с производительностью , а не со стабильностью , поэтому такая ошибка никогда не приведет к сбою. Он просто будет использовать более медленную копию. Кроме того, такая ошибка возникает и для неконстантных объектов, у которых нет конструкторов перемещения, поэтому простое добавление
const
перегрузки не перехватит их все. Мы могли бы проверить возможность перемещения конструкции или перемещения присваивания из типа параметра, но это будет мешать общему коду шаблона, который, как предполагается, использует конструктор копирования. И, черт возьми, может быть, кто-то хочет иметь возможность строить, изconst CAT&&
кого я такой, чтобы сказать, что он не может?источник
const
l, также не поможет. [class.copy] §8: «В противном случае неявно объявленный конструктор копии будет иметь формуX::X(X&)
»Одна из причин, по которой остальные ответы до сих пор упускают из виду, заключается в способности универсального кода быть устойчивым перед лицом перемещения. Например, допустим, что я хотел написать общую функцию, которая перемещала бы все элементы из одного типа контейнера, чтобы создать другой вид контейнера с теми же значениями:
Круто, теперь я могу относительно эффективно создать a
vector<string>
из a,deque<string>
и каждый человекstring
будет перемещен в процессе.Но что, если я захочу переехать из а
map
?Если
std::move
настаивать на отсутствииconst
аргумента, приведенный выше экземплярmove_each
не будет компилироваться, потому что он пытается переместитьconst int
(key_type
изmap
). Но этому коду все равно, если он не может переместитьkey_type
. Он хочет переместитьmapped_type
(std::string
) по соображениям производительности.Именно для этого примера и бесчисленных других примеров, подобных этому в общем кодировании,
std::move
является запрос на перемещение , а не требование на перемещение.источник
Меня беспокоит то же, что и ОП.
std :: move не перемещает объект и не гарантирует подвижность объекта. Тогда почему это называется ходом?
Я думаю, что неподвижность может быть одним из следующих двух сценариев:
1. Тип движения - const.
Причина, по которой у нас есть ключевое слово const в языке, заключается в том, что мы хотим, чтобы компилятор предотвращал любые изменения объекта, определенного как const. Рассмотрим пример из книги Скотта Мейерса:
Что это буквально означает? Переместите константную строку в член значения - по крайней мере, это я понял, прежде чем читать объяснение.
Если язык намеревается не выполнять перемещение или не гарантирует, что перемещение применимо при вызове std :: move (), то при использовании слова move это буквально вводит в заблуждение.
Если язык поощряет людей, использующих std :: move, повысить эффективность, он должен предотвращать подобные ловушки как можно раньше, особенно для этого типа очевидного буквального противоречия.
Я согласен с тем, что люди должны знать, что перемещение константы невозможно, но это обязательство не должно означать, что компилятор может молчать, когда возникает очевидное противоречие.
2. У объекта нет конструктора перемещения.
Лично я думаю, что это отдельная история от беспокойства OP, как сказал Крис Дрю.
источник
Я удивлен, что никто не упомянул об этом аспекте обратной совместимости. Я считаю, что он
std::move
был специально разработан для этого в C ++ 11. Представьте, что вы работаете с устаревшей кодовой базой, которая в значительной степени полагается на библиотеки C ++ 98, поэтому без отката при назначении копии перемещение может сломать ситуацию.источник
К счастью, вы можете использовать проверку clang-tidy, чтобы найти такие проблемы: https://clang.llvm.org/extra/clang-tidy/checks/performance-move-const-arg.html
источник