Есть ли предварительные условия для std :: vector :: push_back?

в комментирует статью конструктора перемещения Анджея, Я написал, что перемещенный объект может иметь любую вызываемую функцию, которая не имеет предварительного условия. Я привел пример 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 ]

1

Решение

Каков контекст конструкторов перемещения, оставляющих объект в допустимом, но неопределенном состоянии, и применяется ли он к потенциальным ситуациям нехватки памяти с помощью std :: vector :: push_back?

Нет, это не относится Имея достаточно памяти, чтобы сделать push_back не является предварительным условием. Нормально звонить push_back когда в системе больше нет памяти (как правило, программа не может знать заранее, будет ли выделение выполнено успешно или нет), и если не хватает памяти, вы получаете исключение. Это просто нормальное поведение push_back не является нарушением предварительного условия.

В частности, если std :: vector :: push_back работал бы до перемещения, гарантированно ли он будет работать после (игнорируя проблемы, такие как другие процессы, использующие память)?

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

Но игнорируя неудачу выделения, push_back будет успешным, и, как говорится в комментарии Говарда, теперь ваш вектор, который ранее имел неизвестное количество элементов, имеет неизвестное число плюс один. Действительный, но не очень полезный.

2

Другие решения

Если памяти недостаточно, то push_back выходит с std::bad_alloc исключение и пост-условие не применяется. vector Объект оставлен в своем первоначальном состоянии.

Когда вектор достигает емкости, вот что происходит:

  1. Выделите больший блок. Если это бросает bad_alloc Исключение, передать его пользователю. Ничто не было изменено.
  2. Если тип не является подвижным, или подвижный, но конструктор перемещения может вызвать исключение, затем скопируйте элементы последовательности в больший блок. Если конструктор выбрасывает исключение, уничтожает все, что уже находится в блоке большего размера, затем освобождает его и затем отбрасывает исключение.
  3. Если тип является подвижным, а конструктор перемещения noexcept, затем переместите элементы в больший блок. Это должно быть успешным. Если это noexcept Если спецификация нарушена, то реализация не должна пытаться переместить вещи назад (что может и, скорее всего, также приведет к сбою).
  4. Уничтожьте оригинальный блок памяти и сохраните новый.

«Действительный, но не уточненный» не имеет более глубокого значения в этом контексте. Пользователь просто не должен делать предположения о том, что в нем. Но проверка его на предмет обнаружения содержимого или игнорирование содержимого и добавление еще — это хорошо.

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

3

По вопросам рекламы [email protected]