我可以创建对空可选值的引用吗?
Can I create a reference to the value of an empty optional?
我看到了以下模式several times:
// 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
和显式析构函数调用。您可以看到它正在运行 here.
现在,std::aligned_storage
很整洁,但是 C++17 为我们提供了一个新工具,用于这种存储与对象生命周期的拆分,即 std::optional
。
但是,访问 std::optional
值的两种方式(value()
和 operator*
)都需要实际存在的值;否则 value()
将抛出 std::bad_optional_access
,而 operator*
将触发未定义的行为(通过打破 [optional.observe]§5 中的 requires 子句)。
std::optional<T> storage;
T &t = *storage; // Looks okay, mines bitcoin when you're not looking
std::optional
这样的用法还能以某种方式使用吗?
如果不是,阻止它的原因是什么?
This, coupled with adequate namespacing and naming, provides a pleasant interface (t) to users of the variable, while enabling deferred construction, reinitialization, etc of the actual object on the library side.
不幸的是,使用 t
访问稍后在该地址构造的对象是未定义的行为。这是 reasons 提出 std::launder
的原因之一。
请注意,这种情况不同于 that question. In that question, the reference/pointer is obtained after the object of type T
is created (though this may also be undefined 中描述的情况,在 C++17 之后没有 std::launder
)。
Is such an usage of std::optional still possible somehow?
正如您所指出的,这是未定义的行为。
If not, what would be a reason for preventing it?
优化器可能会发现该地址与为 T
提供存储的对象相关联,并忽略通过导致未定义行为的类型的 glvalue 对该地址的任何访问。其实原因本质上就是how strict-aliasing rules benefit an optimizer.
我看到了以下模式several times:
// 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
和显式析构函数调用。您可以看到它正在运行 here.
现在,std::aligned_storage
很整洁,但是 C++17 为我们提供了一个新工具,用于这种存储与对象生命周期的拆分,即 std::optional
。
但是,访问 std::optional
值的两种方式(value()
和 operator*
)都需要实际存在的值;否则 value()
将抛出 std::bad_optional_access
,而 operator*
将触发未定义的行为(通过打破 [optional.observe]§5 中的 requires 子句)。
std::optional<T> storage;
T &t = *storage; // Looks okay, mines bitcoin when you're not looking
std::optional
这样的用法还能以某种方式使用吗?
如果不是,阻止它的原因是什么?
This, coupled with adequate namespacing and naming, provides a pleasant interface (t) to users of the variable, while enabling deferred construction, reinitialization, etc of the actual object on the library side.
不幸的是,使用 t
访问稍后在该地址构造的对象是未定义的行为。这是 reasons 提出 std::launder
的原因之一。
请注意,这种情况不同于 that question. In that question, the reference/pointer is obtained after the object of type T
is created (though this may also be undefined 中描述的情况,在 C++17 之后没有 std::launder
)。
Is such an usage of std::optional still possible somehow?
正如您所指出的,这是未定义的行为。
If not, what would be a reason for preventing it?
优化器可能会发现该地址与为 T
提供存储的对象相关联,并忽略通过导致未定义行为的类型的 glvalue 对该地址的任何访问。其实原因本质上就是how strict-aliasing rules benefit an optimizer.