Подтвердить что ты не робот

Почему функции элемента свопинга в контейнерах STL не объявлены noexcept?

В соответствии с N3797 для стандарта С++ требуется swap функции контейнеров, чтобы исключить какие-либо исключения, если не указано иначе [container.requirements.general] (23.2.1§10),

  • Почему функции-члены swap, которые указаны, чтобы не вызывать не объявленные noexcept?

Тот же вопрос относится к специализированным не-членным перегрузкам swap.Суб >

4b9b3361

Ответ 1

В дополнение к что сказал refp, здесь сообщение от Daniel Krügler в списке рассылки std-discussion:

Внутренняя политика для объявления функции как безусловного noexcept объяснено в

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf

С терминологией, используемой в этой статье, функция std::vector swap имеет сужающий контракт, то есть он имеет предварительные условия в отношении распределители участвующих объектов. Это означает, что существует возможность того, что вызывающие могут нарушать предварительные условия и внедрение должно быть позволено сигнализировать об этом другим способом чем путем расторжения. Поэтому такие функции не должны быть исключены, но он должен иметь эффективный элемент "Броски: ничего", потому что это относится к ситуации, когда выполняются предпосылки.

(ссылка)

Указанная внутренняя политика - это канонический, официальный ответ на ваш вопрос.

Ответ 2

Сначала может показаться нечетным, но явно не указано, что swap стандартного контейнера noexcept является намеренным; и все это сводится к undefined поведению (UB).


23.2.1p9 Общие требования к контейнерам [container.requirements.general]

Выражение a.swap(b), для контейнеров a и b стандартного   тип контейнера, отличный от array, должен обмениваться значениями a  и b без вызова операций перемещения, копирования или свопинга на   отдельные элементы контейнера.

     

Любые Compare, Pred или Hash объекты, принадлежащие a и b, должны   быть заменяемым и обмениваться безоговорочными обращениями к нечлену   swap.

     

Если   allocator_traits<allocator_type>::propagate_on_container_swap::value  true, то распределители a и b также должны быть обменены   используя неквалифицированный вызов не-члену swap. В противном случае они должны   не меняться местами, а поведение undefined, если только `a.get_allocator   () == b.get_allocator().

Примечание: курсив, добавленный мной.


Почему предыдущий раздел относится к моему вопросу?

Поскольку swap стандартных контейнеров имеет предварительное условие (самое главное, последний абзац ранее цитируемого раздела стандарта), что может привести к UB, если это не выполнено, стандарт не хочет навязывать "невозможное", ограничения на реализации.


В стандарте говорится следующее о undefined поведении:

1.3.24 undefined поведение [defns.undefined]

Поведение, для которого настоящий международный стандарт не предъявляет никаких требований.


Только преступники и, возможно, продавцы, считали бы Нет чем-то иным, чем Нет, но когда Стандарт говорит "нет требований", это действительно означает " нет требований"; обозначая соответствующие функции swap как noexcept, будет налагать требование на реализации, где их не должно быть.


Почему стандарт не хочет налагать такие требования?

Там интересная статья (N3248) по этому поводу Алисард Мередит и Джон Лакос под названием "noexcept предотвращает проверку библиотеки".

Вкратце он говорит о том, как noexcept предотвратит использование библиотеки asserts в библиотечном коде (т.е. реализации стандартной библиотеки) даже во время режима отладки и последствия этого.

Если С++ имел стандартизованный "тестовый" и "производственный" режимы (как его называет бумага), где noexcept будет условно применяться, это будет гораздо менее проблематично.. но по мере того, как он в настоящее время стоит; С++ не имеет "режимов".