Семантика и исключения С++ Move

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

Остается ли исходный объект? или оба являются исходными и перемещаемыми объектами в состоянии undefined? каковы гарантии, предоставляемые языком?

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

В этом случае возникает вопрос об исключительных гарантиях. Существует 3 типа Гарантий Исключения (применимых к функциям):

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

Когда вы составляете свою функцию, вы обычно получаете существующие функции со своими собственными гарантиями. Трудно увеличить гарантию на исключение, т.е. Ваши обычно ограничены самой слабой гарантией.

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

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

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

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

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

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

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