в комментирует статью конструктора перемещения Анджея, Я написал, что перемещенный объект может иметь любую вызываемую функцию, которая не имеет предварительного условия. Я привел пример std::vector::front
как функция, которую вы не можете вызвать на std::vector
потому что он имеет предварительное условие, что вектор не пуст. Я привел примеры std::vector::empty
, std::vector::push_back
, а также std::vector::reserve
как функции, которые вы можете (но не должны) вызывать std::vector
потому что у них нет предварительных условий.
Однако это заставило меня задуматься. std::vector::push_back
требует, чтобы в хост-системе было достаточно непрерывной памяти. Это не столько требование к std::vector
объект как таковой о системе, на которой он работает, но это все еще кажется предварительным условием.
Каков контекст конструкторов перемещения, оставляющих объект в допустимом, но неопределенном состоянии, и применяется ли он к потенциальным ситуациям нехватки памяти с std::vector::push_back
? В частности, если std::vector::push_back
работал бы до переезда, гарантированно ли он будет работать после (игнорируя такие проблемы, как другие процессы, использующие память)?
Для справки: § 17.6.3.1
Table 20 — MoveConstructible requirements [moveconstructible]
Expression Post-condition
T u = rv; u is equivalent to the value of rv before the construction
T(rv) T(rv) is equivalent to the value of rv before the construction
rv’s state is unspecified [ Note:rv must still meet the requirements of the library compo-
nent that is using it. The operations listed in those requirements must work as specified
whether rv has been moved from or not. — end note ]
Каков контекст конструкторов перемещения, оставляющих объект в допустимом, но неопределенном состоянии, и применяется ли он к потенциальным ситуациям нехватки памяти с помощью std :: vector :: push_back?
Нет, это не относится Имея достаточно памяти, чтобы сделать push_back
не является предварительным условием. Нормально звонить push_back
когда в системе больше нет памяти (как правило, программа не может знать заранее, будет ли выделение выполнено успешно или нет), и если не хватает памяти, вы получаете исключение. Это просто нормальное поведение push_back
не является нарушением предварительного условия.
В частности, если std :: vector :: push_back работал бы до перемещения, гарантированно ли он будет работать после (игнорируя проблемы, такие как другие процессы, использующие память)?
Законно пытаться push_back
но это не гарантировано, чтобы работать. После перемещения хранилище вектора могло быть перемещено к цели перемещения, и push_back
может вызвать перераспределение, которое может потерпеть неудачу и бросить bad_alloc
,
Но игнорируя неудачу выделения, push_back
будет успешным, и, как говорится в комментарии Говарда, теперь ваш вектор, который ранее имел неизвестное количество элементов, имеет неизвестное число плюс один. Действительный, но не очень полезный.
Если памяти недостаточно, то push_back
выходит с std::bad_alloc
исключение и пост-условие не применяется. vector
Объект оставлен в своем первоначальном состоянии.
Когда вектор достигает емкости, вот что происходит:
bad_alloc
Исключение, передать его пользователю. Ничто не было изменено.noexcept
, затем переместите элементы в больший блок. Это должно быть успешным. Если это noexcept
Если спецификация нарушена, то реализация не должна пытаться переместить вещи назад (что может и, скорее всего, также приведет к сбою).«Действительный, но не уточненный» не имеет более глубокого значения в этом контексте. Пользователь просто не должен делать предположения о том, что в нем. Но проверка его на предмет обнаружения содержимого или игнорирование содержимого и добавление еще — это хорошо.
По логике, любой объект должен быть оставлен пустым или в своем первоначальном состоянии. Кажется, я помню, что vector
на самом деле указано, что он оставлен пустым, и многие программисты предполагают, что это правильно или нет.