Почему std :: vector позволяет использовать конструктор с возможностью броска для типа, который он содержит? - PullRequest
2 голосов
/ 27 апреля 2019

Очевидно, std::move_if_noexcept() вызовет конструктор перемещения, даже если он не помечен как noexcept, если конструктор копирования недоступен.

С cpprefeerence.com (выделено мной):

Примечания

Это используется, например, std::vector::resize, которому, возможно, придется выделить новое хранилище, а затем переместить или скопировать элементы из старого хранилища в новое хранилище. Если во время этой операции возникает исключение, std::vector::resize отменяет все, что было сделано до этого момента, что возможно только в том случае, если std::move_if_noexcept использовалось для принятия решения о том, использовать ли конструкцию перемещения или копирования. (если конструктор копирования недоступен, в этом случае конструктор перемещения используется в любом случае и может быть отменена гарантия строгого исключения)

Поскольку std::vector использует эту функцию при перераспределении, это может оставить вектор и, возможно, приложение в неопределенном состоянии. Итак, с чего бы это было разрешено?

1 Ответ

2 голосов
/ 27 апреля 2019

Допустим, вы делаете то, что делает vector, когда будет использоваться move_if_noexcept. То есть у вас есть какой-то объект obj, и вам нужно создать новое значение этого типа из obj. И после этого вы собираетесь удалить obj. Это лучший случай для перемещения объекта, поэтому vector делает это там, где это возможно.

Если движение noexcept, то перемещение obj по определению безопасно. Если это не noexcept, то вам нужно спросить: что произойдет, если сработает конструктор перемещения? Каково состояние obj в этом случае? Ответ ... ты не знаешь. Хуже того, как насчет состояния каких-либо объектов, с которых вы уже успешно переехали? Вы можете переместить их назад ?

Однако, когда дело доходит до копирования конструкторов, вы знаете . Конструктор копирования принимает const& к исходному объекту. Таким образом, по определению, неудачная операция копирования не может изменить obj (и да, мы знаем, что вы можете const_cast, но это делает ваш конструктор копирования ложью . почему auto_ptr больше не существует, и я бы предположил, что в стандарте есть общий запрет на конструкторы ложных копий). Таким образом, в случае неудачной копии obj находится в исходном состоянии.

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

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

Это разрешено, потому что это то, что вы просили . Выбранный вами тип не предусматривает строгой гарантии исключения, поэтому он не может быть предоставлен. Но вы все равно можете сделать vector таких типов; вам просто нужно иметь дело с возможностью не копируемого сбоя движения.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...