fill insert () — копировать конструктор и копировать присвоение noexcept status?

  1. Должны ли элементы контейнера STL иметь noexcept конструкторы копирования и операторы копирования-назначения? Пожалуйста, предоставьте ссылку, если это возможно.
  2. Если нет, то каково состояние контейнера STL, когда исключение происходит во время множественной вставки, например в течение заполнить вкладыш.

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

Например, std::vector имеет заполнить вкладыш:

void insert (iterator position, size_type n, const value_type& val);

Это требует value_type быть одновременно CopyInsertable так же как CopyAssignable. Обратите внимание, что это делает не требует, чтобы тип значения был DefaultConstructible.

Редактировать 3 Страуструп Сам (таблица на стр. 956) указывает, что многоэлементная вставка должен иметь сильная гарантия для всего вектора, deque, списка и карты. Это означает, что полная стандартная операция библиотеки либо выполняется успешно, либо не выполняется атомарно.

Редактировать 4 Однако гарантия применяется только тогда, когда соответствующие операции (в данном случае конструктор копирования) сами по себе не генерируют исключения, что является именно моей проблемой.

Насколько я понимаю, это оставляет два основных метода реализации:

  1. Создайте фиктивный записи для новых элементов и копирования-назначения val, Это работает только тогда, когда возможно создать фиктивные элементы путем копирования существующих элементов в контейнере или когда value_type является DefaultConstructible (что не является обязательным требованием).
  2. Скопируйте и создайте элементы один за другим непосредственно в их соответствующих местах в контейнере. Кажется, это более или менее каноническая реализация.

Редактировать 2: Я не буду называть это неопределенное поведение, потому что этот термин, кажется, заставляет людей задуматься не определено как по языку времени выполнения / стандарту.

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

Редактировать 1Обратите внимание, что это не означает, что я предполагаю, что существует плохое поведение по отношению к среде выполнения C ++, например утечки памяти или неопределенные значения. Тем не менее, кажется, это более или менее неопределенные каково содержимое контейнера. В частности, содержимое контейнера могло быть полностью (хотя и последовательно) изменено.

В качестве примера рассмотрим третий (гибридный) метод:

  1. создать список n копии объекта шаблона val,
  2. скопировать-назначить элементы из этого списка в целевой контейнер.

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

Что касается noexcept на элементах контейнера: объекты создаются с помощью allocator_traits<value_type>::construct(ptr, args)что не noexcept и я также не могу найти требование, чтобы элементы контейнера наиболее noexcept конструктор копирования / оператор копирования (например, std::shared_ptr а также std::unique_ptr требуют этого).

Обратите внимание, что автоматически генерируемые операции для копирования-конструирования и копирования-назначения должны быть noexcept если они не обязаны вызывать операцию, которая сама может вызвать исключение.

Это приводит меня в замешательство, и я уверен, что что-то пропустил, но я не могу понять ту часть стандарта, которая может доказать, что я неправ.

3

Решение

  1. Должны ли элементы контейнера STL иметь исключение кроме конструкторов копирования и операторов назначения копирования? Пожалуйста, предоставьте ссылку, если это возможно.

Нет, их нет, и я не могу предоставить ссылку на требование, которого нет, потому что его нет.

Если бы это было необходимо, то в стандарте это было бы сказано, но это не так.

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

  1. Если нет, то каково состояние контейнера STL, когда исключение происходит во время множественной вставки, например во время заполнения вставить.

Это зависит от контейнера, и где в контейнере вы вставляете.

Для контейнеров на основе узлов, таких как списки, если одна вставка выбрасывает, то все элементы, которые уже были вставлены, остаются в контейнере.

За std::vector что именно происходит, зависит от того, в каком месте вектора вы вставляете и нужно ли перераспределение, и есть ли у элементов конструктор перемещения noexcept, или нет. Все, на что вы можете положиться, это то, что не будет никаких утечек и частично построенных элементов, поэтому вектор находится в допустимом состоянии.

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

Это не неопределенное состояние, это просто состояние, о котором у вас нет полной информации. Ты можешь использовать vector::size() а также vector::capacity() определить его состояние и осмотреть элементы на месте [0, size()) проверить состояние элементов. После этого вы знаете все о состоянии вектора.

то есть вектор всегда находится в действительном состоянии, вы просто не знаете достаточно информации, чтобы точно описать это состояние, пока не осмотрите его.

Слово «неопределенный» предполагает, что состояние является непоследовательным или непознаваемым, что не соответствует действительности. Стандартные контейнеры всегда дают базовая гарантия безопасности поэтому неудачные операции не оставят их в неопределенном состоянии.

Даже в крайнем случае, например vector::push_back() где тип элемента не подлежит копированию и имеет конструктор броска, исключение оставит вектор в «неопределенном» состоянии, поэтому нет утечек, недопустимых объектов и неопределенного поведения.

В качестве примера рассмотрим третий (гибридный) метод:

  • создать список из n копий шаблона объекта val.
  • скопировать-назначить элементы из этого списка в целевой контейнер.

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

Может быть, я неправильно понимаю, но я не вижу, как это лучше, чем «Копировать-конструировать элементы один за другим прямо в соответствующие места в контейнере». Он выполняет значительно больше работы, выполняя N конструкций копирования и N назначений копирования вместо N конструкций копирования, и я не вижу никаких преимуществ с точки зрения конечного состояния контейнера.

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

5

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector