Возможно ли иметь типы с операциями перемещения, которые выбрасывают контейнеры?
Объясняя операции перемещения над объектами с коллегой, я в основном говорил, что операции перемещения не должны генерировать исключения в контейнере, потому что если операция перемещения не удалась, то нет способа надежно вернуть исходный объект. Думая об этом больше, я задаюсь вопросом, если это не правильно, и что если операция перемещения, которая бросает, она может вернуть исходный объект обратно в исходное состояние.
Причина этого в том, что если объект может генерировать объект, то он будет генерировать объект не из-за копирования или перемещения содержащихся объектов со старого на новый адрес, а в случае сбоя при получении ресурса. Так что вся оригинальная информация все еще должна быть там. Если это так, то должен ли компилятор быть в состоянии отменить операции, которые он сделал для восстановления исходного объекта?
Возможно, что операция может быть односторонней, например, перемещение целого числа, но в этом случае она может просто завершить приложение, и, возможно, если разработчик хочет избежать односторонней операции, он может вместо этого использовать метод подкачки.
Это было бы возможно только для операторов перемещения по умолчанию, так как если есть какая-либо дополнительная логика, компилятору может быть трудно выполнить обратное частичное преобразование.
Я упрощаю вещи? Есть ли что-то, что я пропустил, что удерживает контейнеры от движущихся объектов без конструктора / оператора перемещения без броска?
2 ответа
Вы можете использовать типы с бросанием ходов в контейнерах, таких как vector
которые могут перемещать свои элементы. Однако такие контейнеры не будут использовать операции перемещения броска.
Допустим, у вас есть vector
из 10 элементов броска хода. И vector
нужно изменить размер себя. Таким образом, он перемещает 5 объектов в новую память, но 6-й бросок. Ну, все в порядке; строительство не удалось, поэтому предположение, что стоимость 6-го объекта в порядке. То есть, какой бы ни была гарантия исключения этого типа, будет то, как все будет работать.
Но тогда, потому что движение одного объекта не удалось, vector
необходимо переместить последние 5 объектов обратно в первый массив, так как vector
пытается предоставить сильную гарантию исключения. Это проблема, потому что сам переход назад может провалиться.
C++ в общем случае не имеет правильных ответов, когда сам процесс восстановления неисправности завершается неудачей. Вы можете видеть это в исключениях; вы не можете создать исключение из деструктора, который вызывается в процессе разматывания из-за сбоя исключения. std::terminate
бывает в этом случае.
То же самое касается vector
, Если движение назад провалилось, vector
не имеет вменяемого ответа. Как таковой, если vector
не может гарантировать, что восстановление предыдущего состояния массива noexcept
затем он будет использовать копирование, поскольку это может обеспечить такую гарантию.
Прежде всего, я с трудом могу представить объект, который получает ресурсы в операции перемещения. Думаю об этом - unique_ptr
просто передает указатель, не получая ничего, то же самое для shared_ptr
, string
, vector
все контейнеры и т. д. просто крадут указатели на ресурсы, полученные ранее в конструкторе default или copy. Я чувствую, что бросать из конструктора движения - это как бросать из деструктора. Конечно, давай, стреляй себе в колено. Но хорошо, я могу принять, что исключения из этого существуют.
Итак, давайте перейдем ко второй точке - при перемещении может быть момент, когда фактически оба объекта (перемещенные и перемещенные в) являются недействительными. А для отката из такой ситуации потребуется дополнительная "магическая" функция, чтобы исправить одну из них. Таким образом, кажется, что данные не могут быть восстановлены, так как стандарт не определяет такую функцию.