Что я могу сделать с перемещенным объектом?

141

Определяет ли стандарт точно, что я могу делать с объектом после его перемещения? Раньше я думал, что все, что вы можете сделать с перемещенным объектом, - это уничтожить его, но этого было бы недостаточно.

Например, возьмите шаблон swapфункции, определенный в стандартной библиотеке:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Очевидно, что должна существовать возможность присвоения перемещенным объектам, иначе строки 2 и 3 не будут работать. Итак, что еще я могу сделать с удаленными объектами? Где именно в стандарте можно найти эти детали?

(Кстати, а почему T c = std::move(a);вместо T c(std::move(a));строки 1?)

fredoverflow
источник

Ответы:

54

Перемещенные объекты существуют в неуказанном, но допустимом состоянии. Это говорит о том, что, хотя объект, возможно, больше не может делать много, все его функции-члены должны по-прежнему демонстрировать определенное поведение - включая operator=- и все его члены в определенном состоянии - и он по-прежнему требует уничтожения. Стандарт не дает конкретных определений, потому что он будет уникальным для каждого UDT, но вы можете найти спецификации для стандартных типов. Некоторые подобные контейнеры относительно очевидны - они просто перемещают свое содержимое, и пустой контейнер является четко определенным допустимым состоянием. Примитивы не изменяют перемещенный объект.

Боковое примечание: я считаю, T c = std::move(a)что если конструктор перемещения (или конструктор копирования, если перемещение не предусмотрено) явным образом, функция завершится ошибкой.

Щенок
источник
26
Не все его функции-члены будут демонстрировать определенное поведение. Только без предварительных условий. Например, вы, вероятно, не хотите pop_backпереезжать vector. Но вы, конечно, можете узнать, так ли это empty().
Ховард Хиннант,
6
@Howard Hinnant: pop_backиз пустого в vectorлюбом случае поведение undefined, из памяти, поэтому я почти уверен, что pop_backиз перемещенного вектора, показывающего поведение undefined, согласовано.
Puppy
12
Мы обсуждаем перенесенные объекты. Не объекты, о которых известно, что они находятся в пустом состоянии. У перемещенных объектов неопределенное состояние (если, конечно, не указано иное). [lib.types.movedfrom]
Говард Хиннант
5
@Howard Не указан, но действителен, поэтому по- pop_backпрежнему ведет себя как любой допустимый вектор (может быть даже пустой вектор).
Кристиан Рау,
1
что в данном контексте означает неуказанный и действительный?
Ankur S
116

17.6.5.15 [lib.types.movedfrom]

Объекты типов, определенных в стандартной библиотеке C ++, могут быть перемещены из (12.8). Операции перемещения могут быть заданы явно или неявно. Если не указано иное, такие перемещенные объекты должны быть переведены в допустимое, но не определенное состояние.

Когда объект находится в неопределенном состоянии, вы можете выполнить любую операцию с объектом, которая не имеет предварительных условий. Если есть операция с предварительными условиями, которые вы хотите выполнить, вы не можете напрямую выполнить эту операцию, потому что вы не знаете, удовлетворяет ли неопределенное состояние объекта предварительным условиям.

Примеры операций, которые обычно не имеют предварительных условий:

  • разрушение
  • назначение
  • константные наблюдатели , такие как get, empty,size

Примеры операций, которые обычно имеют предварительные условия:

  • разыменование
  • pop_back

Этот ответ теперь отображается здесь в формате видео: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s

Говард Хиннант
источник
1
Но я мог бы просто проверить предварительные условия, как и с любым другим объектом, верно?
fredoverflow
6
@FredOverflow, если, конечно, сами эти проверки не имеют предварительных условий.
Christian Rau
1
@Chris: Но чем это отличается от обычного, не перемещенного объекта?
fredoverflow
2
Может быть, должен быть отдельный вопрос, но это значит: если у меня есть строка с char* buffer;и int length;членами, то мой ход конструктор / назначение сусло замены (или набор) значение обоих? Или было бы нормально, если бы длина не была указана (то есть, emptyи sizeвозвращала бы бессмысленные значения)?
UncleBens
3
@ 6502: В тебе нет смысла. Класс C ++ 03 не «нарушает стандарт C ++ 0x», потому что сгенерированный объект перемещения нарушит стандарт. И код C ++ 03 не будет перемещать этот класс, поэтому нет причин для создания объекта перемещения.
MSalters