Я видел следующую картину несколько раз:
// T is a type, this is at namespace scope
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
T &t = reinterpret_cast<T &>(storage);
Это, в сочетании с адекватным пространством имен и имен, обеспечивает приятный интерфейс (t
) для пользователей переменной, обеспечивая возможность отложенного построения, повторной инициализации и т. д. реального объекта на стороне библиотеки при размещении new
и явные вызовы деструкторов. Вы можете видеть это работает Вот.
Сейчас, std::aligned_storage
и все, но C ++ 17 дал нам новый инструмент для такого разделения времени хранения объекта хранения, то есть std::optional
,
Тем не менее, два способа доступа к значению std::optional
(value()
а также operator*
) оба требуют значения, чтобы действительно быть там; иначе value()
будет бросать std::bad_optional_access
, в то время как operator*
вызовет неопределенное поведение (за нарушение требует пункт в [Optional.observe] § 5).
std::optional<T> storage;
T &t = *storage; // Looks okay, mines bitcoin when you're not looking
Такое использование std::optional
все еще возможно как-то?
Если нет, что было бы причиной для предотвращения этого?
Это, в сочетании с адекватным пространством имен и именами, обеспечивает приятный интерфейс (t) для пользователей переменной, в то же время обеспечивая отложенное создание, повторную инициализацию и т. Д. Реального объекта на стороне библиотеки.
К сожалению, используя t
доступ к объекту, созданному позже по этому адресу, является неопределенным поведением. Это один из причины Зачем std::launder
предлагается.
Обратите внимание, что этот случай отличается от случая, описанного в этот вопрос. В этом вопросе ссылка / указатель получается после объект типа T
создается (хотя это также может быть неопределенным после C ++ 17 без std::launder
).
Такое использование std :: option все еще возможно?
Как вы указали, это неопределенное поведение.
Если нет, что было бы причиной для предотвращения этого?
Оптимизатор может обнаружить, что адрес связан с объектом, который предоставляет хранилище для T
и игнорировать любой доступ к этому адресу через glvalue типа, который вызывает неопределенное поведение. На самом деле, причины по существу как правила строгого наложения приносят пользу оптимизатору.
Других решений пока нет …