C ++ Move семантика и исключения - PullRequest
26 голосов
/ 19 января 2011

Что произойдет, если в готовящемся стандарте C ++ 0x возникнет исключение в / во время конструктора перемещения?

Сохранится ли исходный объект?или оба объекта находятся в неопределенном состоянии?Какие гарантии дает язык?

Ответы [ 3 ]

10 голосов
/ 19 января 2011

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

Предложение N3050, "Разрешить бросать конструкторы (Rev 1)", было включено в проект стандарта. По сути, в предложении добавлена ​​возможность бросать конструкторы перемещения, но запрещены «бросающие» ходы, которые будут использоваться для определенных операций, где требовались строгие гарантии безопасности исключений (библиотека вернется к копированию объекта, если не выбрасывающий ход не существует) т в наличии).

Если вы пометите конструктор перемещения как невыбрасывающий (noexcept) и будет сгенерировано исключение, будет вызвана std :: terminate ().

Возможно, стоит прочитать статью Дэвида Абрахамса в блоге, в которой обсуждаются проблемы, которые N3050 должен был решить:

3 голосов
/ 19 января 2011

Зависит от типа перемещаемого. Разумеется, можно явно выбрасывать исключение из ctor-перемещения, но также неявно вызывать ctor-копию для подобъекта из ctor-перемещения. Этот экземпляр ctor может делать что-то, что может выдать, например выделять память. Таким образом, для исходного объекта минимальной гарантией является то, что первоначальное значение может сохраняться или не сохраняться, но оно все равно должно находиться в разрушаемом состоянии.

Для объекта, к которому перемещается, это то же самое, что и бросание из ctor в текущем C ++: уничтожить все созданные базы и члены, выполнить обработчик попытки функции ctor, если таковой имеется, затем распространить исключение. Подробности в N3225 §15.2p2.

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

Такая конструкция перемещения распределителя не должна выходить через исключение. [N3225 §23.2p8]

Это позволяет контейнерам перемещать распределители и использовать эти распределители для очистки своих элементов в случае исключения при перемещении или копировании элементов.

2 голосов
/ 19 января 2011

Ваш вопрос тогда сводится к вопросу о гарантиях исключения. Существует 3 типа гарантий исключений (которые применяются к функциям):

  • Никаких исключительных гарантий вообще (на самом деле это не тип ... но это может произойти, если этот вопрос не проявляется)
  • Базовая гарантия исключений : технически правильная, но не функционально правильная (т. Е. Нет утечки ресурса, программа завершается без резкой остановки, но может иметь нежелательные побочные эффекты, такие как обналичивание платежа) -в, но команда не регистрируется)
  • Сильная гарантия исключения : Все или ничего (например, транзакция), то есть либо все сделано правильно, либо мы возвращаемся к предыдущему состоянию.
  • Гарантия исключения без броска : Это не бросает, так что не беспокойтесь.

Когда вы составляете свою функцию, вы обычно выбираете существующие функции со своими собственными гарантиями. Сложно увеличить гарантию исключения, т. Е. Обычно вы ограничены самой слабой гарантией.

W.r.t ваш вопрос, требуется, по крайней мере, Сильная гарантия исключения , если исходный объект остается нетронутым, если выдается исключение.

Итак, что произойдет, если во время построения движения будет сгенерировано исключение? Это зависит от гарантий, предоставленных подобъектами, и способа объединения вызовов ...

  1. Если из конструктора выдается исключение, объект не создается, а все созданные подобъекты уничтожаются в обратном порядке. Это правило также применимо к движению-конструктору
  2. Если вы не «обернете» конструктор в попытку, и каким-то образом восстановите объекты, которые были перемещены, они потеряют свои ресурсы. Обратите внимание, что они все равно должны находиться в разрушаемом состоянии, поэтому технически программа будет правильной.

С точки зрения гарантий исключений это означает, что по умолчанию, если все конструкторы подобъектов хотя бы соответствуют Базовой гарантии исключений , тогда ваш конструктор перемещения тоже будет без особой заботы.

Однако, даже если все конструкторы подобъектов соответствуют Сильному исключению , маловероятно, что ваш собственный конструктор перемещения встретит его: это та же проблема, что цепочка транзакций не дает транзакция.

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

Надеюсь, это помогло ... исключения - это дикий зверь, который можно приручить:)

...