Що я можу зробити з переміщеним об'єктом?


138

Чи визначає стандарт точно, що я можу зробити з об'єктом після його переміщення? Раніше я думав, що все, що ти можеш зробити з переміщеним об'єктом - це знищити його, але цього було б недостатньо.

Наприклад, візьміть шаблон функції, 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?)

Відповіді:


53

Перемещені об'єкти існують у не визначеному, але дійсному стані. Це говорить про те, що, хоча об'єкт може бути нездатний робити більше, всі його функції повинні все-таки проявляти певну поведінку - в тому числі operator=- і всіх її членів у визначеному стані, і це все ще потребує знищення. Стандарт не дає конкретних визначень, оскільки він був би унікальним для кожного UDT, але ви можете знайти специфікації для типів Standard. Деякі на зразок контейнерів відносно очевидні - вони просто переміщують свій вміст навколо, а порожній контейнер - це чітко визначений дійсний стан. Примітиви не змінюють переміщений об'єкт.

Бічна примітка: Я вважаю, що T c = std::move(a)так, якщо конструктор переміщення (або конструктор копіювання, якщо не передбачено переміщення) є явним, функція не буде працювати.


26
Не всі його членські функції демонструватимуть певну поведінку. Тільки ті, що не мають передумов. Наприклад, ви, мабуть, не хочете pop_backпереїхати з vector. Але ви, звичайно, можете дізнатися, чи це так empty().
Говард Хінант

6
@Howard Hinnant: pop_backз порожнього vectorвсе-таки невизначена поведінка в будь-якому випадку, з пам'яті, тому я майже впевнений, що pop_backз переміщеного вектора, що проявляє не визначену поведінку, є послідовним.
Щеня

12
Ми обговорюємо переміщені об'єкти. Не об'єкти, які, як відомо, перебувають у порожньому стані. Об'єкти, що переміщуються, мають не визначений стан (якщо, звичайно, не вказано інше). [lib.types.movedfrom]
Говард Hinnant

5
@Howard Невизначений, але дійсний, тому pop_backвсе ще веде себе як на будь-якому дійсному векторі (нехай це може бути навіть порожній вектор).
Крістіан Рау

1
що означають у цьому контексті невизначене та дійсне?
Ankur S

114

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 До тих пір, поки самі ці перевірки не мають жодних передумов.
Крістіан Рау

1
@Chris: Але чим це відрізняється від нормального, а не переміщеного від об'єкта?
fredoverflow

2
Може бути окремим питанням, але чи означає це: якщо у мене є рядок з char* buffer;і int length;членами, то мій конструктор переміщення / призначення повинен змінити (або встановити) значення обох? Або було б нормально, якби довжина була не визначена (маючи на увазі це emptyі sizeповертає безглузді значення)?
UncleBens

3
@ 6502: Ви не маєте сенсу. Клас C ++ 03 не "порушує стандарт C ++ 0x", оскільки ctor переміщення, якщо створений , порушує стандарт. І код C ++ 03 не переміщуватиме цей клас, тому немає ніякого приводу для створення генератора переміщення.
MSalters
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.