Подтвердить что ты не робот

Почему вы используете std:: move, когда у вас есть && в С++ 11?

Possible Duplicate:
What is move semantics?

Недавно я посетил семинар по С++ 11, и мне дали следующий небольшой совет.

when you have && and you are unsure, you will almost always use std::move

Может ли кто-нибудь объяснить мне, почему вы должны использовать std::move, в отличие от некоторых альтернатив и в некоторых случаях, когда вы не должны использовать std::move?

4b9b3361

Ответ 1

Во-первых, вероятно, есть неправильное представление в вопросе, который я адресую:
Всякий раз, когда вы видите T&& t в коде (и T - это фактический тип, а не тип шаблона), имейте в виду, что категория значений t - это lvalue (reference), а не rvalue (временная). Это очень запутанно. T&& просто означает, что t строится из объекта, который был rvalue 1 но t сам является lvalue, а не rvalue. Если у него есть имя (в этом случае t), то это значение lvalue и не будет автоматически перемещаться, но если оно не имеет имени (результат 3+4), то оно является rvalue и будет автоматически перемещаться в него результат, если это возможно. Тип (в данном случае T&&) почти не имеет ничего общего с категорией значений переменной (в данном случае, lvalue).

Если у вас есть T&& t, написанный в вашем коде, это означает, что у вас есть ссылка на переменную, которая была временной, и ее можно уничтожить, если хотите. Если вам нужно получить доступ к переменной несколько раз, вы не хотите std::move от нее, иначе она потеряет ее значение. Но в последний раз, когда вы получаете t, безопасно std::move присвоить значение другому t, если хотите. (И 95% времени, что вы хотите сделать). Все это также относится к переменным auto&&.

1. если t является типом шаблона, T&& вместо этого используется ссылка пересылки, в этом случае вы используете std::forward<T>(t) вместо std::move(t) в последний раз. См. этот вопрос.

Ответ 2

Я нашел эту статью, чтобы быть довольно просвещенным в отношении ссылок на rvalue вообще. Он упоминает std::move к концу. Это, вероятно, самая важная цитата:

Нам нужно использовать std::move, от <utility> - std::move - это способ говоря: "Хорошо, честно к Богу, я знаю, что у меня есть значение, но я хочу, чтобы он быть rvalue." std::move сам по себе не перемещает ничего; просто превращает lvalue в rvalue, так что вы можете вызвать ход конструктор.


Скажем, у вас есть конструктор перемещения, который выглядит так:

MyClass::MyClass(MyClass&& other): myMember(other.myMember)
{
    // Whatever else.
}

Когда вы используете оператор other.myMember, возвращаемое значение является значением lvalue. Таким образом, код использует конструктор копирования для инициализации this->myMember. Но так как это конструктор перемещения, мы знаем, что other является временным объектом, а значит, и его членами. Поэтому мы действительно хотим использовать более эффективный конструктор перемещения для инициализации this->myMember. Используя std::move, убедитесь, что компилятор рассматривает other.myMember как ссылку на rvalue и вызывает конструктор перемещения, как вы хотите:

MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember))
{
    // Whatever else.
}

Просто не используйте std::move на объектах, которые вам нужно поддерживать - перемещение конструкторов в значительной степени гарантировано замаскирует любые объекты, переданные в них. Вот почему они используются только с временными.

Надеюсь, что это поможет!

Ответ 3

Если у вас есть объект типа T&&, значение rvalue, это означает, что этот объект безопасен для перемещения, поскольку позже никто не будет зависеть от его внутреннего состояния.

Поскольку перемещение никогда не должно быть дорогим, чем копирование, вы почти всегда захотите его переместить. И чтобы переместить его, вы должны использовать функцию std::move.

Когда вам следует избегать std::move, даже если это будет безопасно? Я бы не использовал его в тривиальных примерах, например:

 int x = 0;
 int y = std::move(x);

Кроме того, я не вижу недостатков. Если это не усложняет код, перемещение должно выполняться по возможности ИМХО.

Другой пример, когда вы не хотите перемещать, - это возвращаемые значения. Язык гарантирует, что возвращаемые значения (по крайней мере) перемещены, поэтому вы не должны писать

return std::move(x); // not recommended

(Если вам повезет, обратная оптимизация значений, что даже лучше, чем операция перемещения.)

Ответ 4

Вы можете использовать перемещение, когда вам нужно "переносить" содержимое объекта в другое место, не делая копии. Также возможно, чтобы объект взял содержимое временного объекта, не делая копию, с std:: move.

Оформить эту ссылку