Для некоторых стандартных библиотечных классов доступ к частям их содержимого может законно завершиться ошибкой. Обычно у вас есть выбор между некоторым потенциально бросающим методом методом и тем, который помечен noexcept
. Последний избавляет от проверки предусловия, поэтому, если вы хотите взять на себя ответственность, вы можете это сделать. Это можно использовать в обстоятельствах, когда использование исключений не разрешено, или при устранении узких мест в производительности.
Пример 1. Доступ к элементу std::vector
:
std::vector<int> vec;
vec.at(n) // throws std::out_of_range
vec[n] // potentially UB, thus your own responsibility
Пример 2: std::optional
доступ:
std::optional<int> optn;
optn.value() // throws std::bad_optional_access
*optn // potentially UB, thus your own responsibility
Теперь перейдем к std::variant
. Прямой доступ к альтернативе отчасти следует этой схеме:
std::variant<std::string, int> var;
std::get<int>(var) // potentially throwing std::bad_variant_access
*std::get_if<int>(&var) // potentially UB, thus your own responsibility
Но на этот раз подпись меняется, мы должны ввести *
и &
. Обратной стороной этого является то, что мы не получаем семантику автоматического перемещения. Еще одна вещь, о которой нужно помнить ...
Но становится еще хуже, если вы посмотрите на std::visit(Visitor&& vis, Variants&&... vars)
. Альтернативы ему нет noexcept
, хотя только выкидывает
если какой-либо вариант в vars является valueless_by_exception.
Это означает, что при посещении вариантов вы не можете взять на себя ответственность, а если у вас нет выбора и вы должны избегать исключений, вы вообще не можете посещать std::variants
со стандартными инструментами! (кроме ужасного обходного пути switch
ing на variant::index()
)
На мой взгляд, это выглядит как очень плохая оплошность в дизайне ... или есть ли этому причина? И если я прав насчет недосмотра, есть ли инициатива исправить это в стандарте?