В C++ мы можемобъявитьобъектом (переменным) типа<T
>, и мы можем дать этой переменной.Начальное значение(через инициализатор)(ср. 8.5)). Когда декларация включает в себя непустый инициализатор (приводится начальное значение), говорят, что объект был инициализирован. Если в декларации используется пустой инициализатор (первоначальное значение не дано), и не применяется ни по умолчанию, ни инициализация значения, говорят, что объектнеинициализирован.. Его фактическое значение существует, но имеетнеопределенное начальное значение(см. 8.5/11).<optional<T>
>намеревается формализовать понятие инициализации (или его отсутствия), позволяя программе проверить, был ли объект инициализирован, и заявляя, что доступ к значению неинициализированного объекта является неопределенным поведением. То есть, когда переменная объявлена как<optional<T>
>и начальное значение не дано, переменнаяформальнонеинициализирована. Формально неинициализированный необязательный объект концептуально не имеет никакой ценности, и эта ситуация может быть протестирована во время выполнения. Формальнонеопределенное поведениепытается получить доступ к значению неинициализированного опционального. Неинициализированному опциональному может быть присвоено значение, в этом случае его состояние инициализации изменяется на инициализированное. Кроме того, учитывая формальную трактовку состояний инициализации в факультативных объектах, можно даже сбросить факультативный нанеинициализированный.
В C++ нет формального понятия неинициализированных объектов, что означает, что объекты всегда имеют начальное значение, даже если они неопределенны. Как обсуждалось в предыдущем разделе, это имеет недостаток, потому что вам нужна дополнительная информация, чтобы определить, был ли объект фактически инициализирован. Один из типичных способов, которыми это исторически рассматривалось, заключается в особой ценности:<EOF
>,<npos
>, -1 и т. д. Это эквивалентно добавлению специального значения к набору возможных значений данного типа. Этот супер-набор<T
>плюс некоторыеnil_t& #8212; где<nil_t
>является не имеющим гражданства POD— может быть смоделирован в современных языках какдискриминируемый союзT и nil_t. Дискриминированные союзы часто называютвариантами. Вариант имееттекущий тип, который в нашем случае либо<T
>, либо<nil_t
>. Используя библиотекуBoost.Variant, эта модель может быть реализована в терминах<boost::variant<T,nil_t>
>. Существует прецедент дискриминируемого союза как модели для факультативной стоимости:HaskellВозможновстроенный конструктор типа. Таким образом, дискриминируемый союз<T+nil_t
>служит концептуальной основой.
A<variant<T,nil_t>
>естественно следует из традиционной идиомы расширения диапазона возможных значений, добавляя дополнительное сторожевое значение с особым значением.Ничего. Однако это дополнительноНичтоне является в значительной степени неуместным для нашей цели, поскольку наша цель состоит в том, чтобы формализовать понятие неинициализированных объектов и, хотя для передачи этого значения может использоваться специальное расширенное значение, для этого нет строгой необходимости.
Замечание, сделанное в последнем пункте о нерелевантном характере дополнительного<nil_t
>в отношениицели<optional<T>
>, предполагает альтернативную модель: контейнер, который либо имеет значение<T
>, либо ничего.
На момент написания этой статьи я не знаю ни одного прецедента для модели контейнера с переменной фиксированной емкостью (из 1) на основе стека для необязательных значений, но я считаю, что это является следствием отсутствия практической реализации такой модели контейнера, а не неотъемлемым недостатком модели контейнера.
В любом случае, как дискриминируемый союз, так и одноэлементные контейнерные модели служат концептуальной основой для класса, представляющего факультативные—т.е., возможно, неинициализированные—объекты. Например, эти модели показываютточнуюсемантику, необходимую для обертки дополнительных значений:
Дискриминированный союз:
- глубокая копиясемантика: копии варианта подразумевают копии значения.
- глубокореляционнаясемантика: сравнения между вариантами соответствуют как текущим типам, так и значениям
- Если текущий тип варианта<
T
>, он моделируетинициализированныйопциональный.
- Если текущий тип варианта не<
T
>, он моделируетнеинициализированныйнеобязательный.
- Тестирование, если текущий тип варианта<
T
>модели тестирования, если опциональный инициализирован
- Попытка извлечь<
T
>из варианта, когда его текущий тип не<T
>, моделирует неопределенное поведение попытки получить доступ к значению неинициализированной опции.
Одноэлементный контейнер:
- глубокая копиясемантика: копии контейнера подразумевают копии значения.
- глубокореляционнаясемантика: сравнения между контейнерами сравнивают размер контейнера и, если совпадают, содержащее значение
- Если контейнер не пустой (содержит объект типа<
T
>), он моделируетинициализированныйнеобязательный.
- Если контейнер пуст, он моделируетнеинициализированныйопциональный.
- Тестирование, если контейнер является пустым, тестирование моделей, если факультативный инициализирован
- Попытка извлечь<
T
>из модели пустого контейнера неопределенное поведение попытки получить доступ к значению неинициализированной опции.