Вот кстати реальный пример, не уверен правильно ли применяю.
Foo = class
{
private:
string _s;
public:
Foo(const char* s):
_s(s)
{}
};
vector<Foo> items;
void addItem(const char* s)
{
Foo item(s);
items.push_back(std::move(item));
}
Без move тут выходит в списке будет невалидный объект, а с move все в порядке, он туда "переместится"?
Валидный будет и там, и там. 11 стандарт дал возможность вылавливать объекты, которые временные или вот-вот умрут (через перегрузку, сигнатуры с rvalue). Без move вы полностью копируете item (внутренний стринг, выделяя место в хипе, вызывается дефолтный оператор= с lvalue). С move же можно просто забрать ресурсы у умирающего объекта и не делать дорогих телодвижений в хипе (вызовется дефолтный оператор= с rvalue). Конечно, можете тянуть шлейф указателей и указателей на указатели (если необходимо заменить объект другим внутри алгоритма). Или же делать сделать в стиле чистого Си:
void copy(Obj &dest, Obj &src) {
/* здесь проиводим полное копирование (открываем новые хенделы на какие-то
* ресурсы (семафоры, мьютексы, память, что угодно еще). На выходе два
* имеем два валидный объекта
*/
}
void copy_from_temp(Obj &dest, Obj &src) {
/* здесь забираем ресурсы у src (не открываем новые хенделы на какие-то
* ресурсы (семафоры, мьютексы, память, что угодно еще). На выходе один
* валидный объект - dest
*/
}
Конечно, если внутри Obj не хранит никаких ресурсов, то разницы в этих функциях
не бдет никакой. Новые кресты делают за нас львиную долю всей этой возни - сами
поймут, что объект временный (иногода можно подсказать), вызовут нужную перегрузку,
сущности из стд умеют правильно перемещаться (что покрывает 90% нужд).