Почему функции элемента свопинга в контейнерах STL не объявлены noexcept?
В соответствии с N3797 для стандарта С++ требуется swap
функции контейнеров, чтобы исключить какие-либо исключения, если не указано иначе [container.requirements.general]
(23.2.1§10),
- Почему функции-члены
swap
, которые указаны, чтобы не вызывать не объявленные noexcept
?
Тот же вопрос относится к специализированным не-членным перегрузкам swap
.Суб >
Ответы
Ответ 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
будет условно применяться, это будет гораздо менее проблематично.. но по мере того, как он в настоящее время стоит; С++ не имеет "режимов".