Для некоторых стандартных библиотечных классов доступ к частям их содержимого может законно завершаться ошибкой.Обычно у вас есть выбор между каким-то потенциально выбрасывающим методом, помеченным 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
на variant::index()
)
Для меня это выглядит довольно плохим упущением дизайна ... или есть причина для этого?И если я прав насчет надзора, есть ли инициатива исправить это в стандарте?