Почему нет throw или sigsegv при доступе к пустому std :: необязательно? - PullRequest
0 голосов
/ 07 ноября 2018

Пример:

#include <optional>
#include <iostream>

using namespace std;

int main()
{
    optional<int> t{}; // nullopt (empty) by default

    cout << *t << endl;

    return 0;
}

На самом деле эта программа печатает некоторое int (неинициализированное значение типа int). Кроме того, libcxx использует assert-check для доступа к незанятому значению.

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

Ответы [ 3 ]

0 голосов
/ 07 ноября 2018

Поскольку это неопределенное поведение, в разделе [необязательный .observe] p5 говорится:

Требуется: * содержит значение.

и нарушение условия require является неопределенным поведением, начиная с [res.on.required # 1] p1 , что соответствует общебиблиотечным требованиям :

Нарушение любых предварительных условий, указанных в функции Требуется: элемент, приводит к неопределенному поведению, если только элемент функции Throws: не определяет выбрасывание исключения при нарушении предварительного условия.

Так что у вас нет никаких ожиданий относительно результата. Из определения неопределенное поведение :

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

Требование проверки реализации будет стоить, и не все пользователи захотят взять эту стоимость. Так что это становится вопросом качества реализации. Реализация может выполнять проверки в различных режимах работы, например, когда утверждения включены.

У пользователя есть возможность взять стоимость самостоятельно через has_value или value_or . Если пользователь хочет выполнить операцию, которая может выдать, он может использовать значение .

Обратите внимание, что sigsegv, segfaults и т. Д. ... - это поведение, определяемое реализацией .

0 голосов
/ 07 ноября 2018

C ++ охватывает идею неопределенного поведения.

Не все операции C ++ имеют поведение, определенное стандартом. Это позволяет компиляторам предполагать, что они никогда не происходят, и во многих случаях может привести к гораздо более быстрому коду.

Здесь, если оставить результат использования неотключенного std::optional неопределенным, то это стоимость доступа к данным, хранящимся в std::optional, равна стоимости доступа к данным, не сохраненным в std::optional. Единственные затраты - это дополнительная комната, и вы, как программист, пообещаете отследить, занят он или нет.

Теперь компиляторы могут свободно вставлять туда проверки, а некоторые делают в отладочных сборках.

Обратите внимание, что обычно типы библиотек C ++ std включают безопасный и небезопасный методы доступа к данным.

Тот факт, что неверные указатели иногда приводят к появлению сигсева, объясняется тем, что большинство ОС защищают адреса около 0 и аварийно завершают программы, которые обращаются к нему. Это потому, что это было дешево, и оно улавливает кучу плохого поведения во многих программах на ассемблере, C и C ++.

Если вы хотите опционально бросать, когда пусто, используйте .value(). Если нет, используйте operator*. Если вам нужно значение по умолчанию, если его там нет, используйте .value_or.

0 голосов
/ 07 ноября 2018

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

Поскольку требование определенного поведения неявно накладывает требование добавить ветку, чтобы проверить, должно ли происходить это поведение - будь то выбрасывание или что-то еще.

Указывая, что поведение не определено, стандарт позволяет реализации не проверять, является ли необязательный параметр пустым при каждом косвенном обращении. Ветвление выполнения потенциально медленнее, чем не ветвление.

Вместо того, чтобы предписывать безопасность, комитет разрешил разработчикам стандартной библиотеки выбирать производительность (и простоту). Реализация, которую вы протестировали, похоже, не выбрала исключение или иным образом не уведомила вас об ошибке.

...