#c
#c
Вопрос:
Следующий код:
std::optional<std::string> so;
std::cout << so->size() << std::endl;
std::cout << so.has_value();
выводит:
0
0
Мой вопрос в том, безопасно ли вызывать: so->size()
для пустого необязательного. Я использовал clang sanitizer, но он не сообщил ни о каком UB в приведенном выше коде.
Комментарии:
1. Это, конечно, не определено так же, как
std::string* so=nullptr; so->size();
было бы не определено.2. @AyxanHaqverdili если это то же самое, что разыменование нулевого указателя, то почему clangs UB sanitizer не распознает его? wandbox.org/permlink/aMv4ZOpXZeH7GgDD Он выбрасывает UndefinedBehaviorSanitizer в тривиальных случаях, как в вашем примере, но оставляет std::optional как корректный, если разыменован, будучи пустым.
3. @mike Вероятно, это сложнее обнаружить,
std::optional
потому что разыменованное хранилище является внутреннимstd::optional
. Для примера с указателем легко статически определить, какой указатель естьnullptr
. Это одна из первых вещей, на обнаружение которых запрограммирован статический анализатор кода. Посколькуstd::optional
сложнее определить, содержит ли внутреннее хранилище инициализированный объект или нет, если вы не знаете, какstd::optional
работают внутренние компоненты. Указатель на это хранилище всегда будет действительным указателем на что- то . Трудно понять, является ли это чем-тоT
или просто хранилищем.
Ответ №1:
Использование operator->
пустого std::optional
— это неопределенное поведение, независимо от того, какой тип T
находится внутри std::optional<T>
.
Согласно cppreference на std::optional<T>::operator->
:
Поведение не определено, если
*this
не содержит значения.
Комментарии:
1. Решением без неопределенного поведения является функция-член std::optional::value() , которая выдает std::bad_optional_access, если необязательный параметр пуст.
Ответ №2:
Цитирование текущего рабочего проекта C
20.6.3.6 Наблюдатели [необязательно.наблюдать]
constexpr const T* operator->() const;
constexpr T* operator->();
Предварительные условия: * это содержит значение.
Затем:
16.3.2.4 Подробные спецификации [structure.specifications]
Предварительные условия: условия, которые функция предполагает выполнять при каждом ее вызове; нарушение любых предварительных условий приводит к неопределенному поведению.
Таким образом, это неопределенное поведение.
Ответ №3:
Вы вызываете optional
конструктор по умолчанию (1 в этой ссылке), который…
- Создает объект, который не содержит значения.
Когда вы переходите к разыменованию…
Поведение не определено, если *this не содержит значения.
Чего в вашем случае нет. Итак, да, у вас есть UB.