【发布时间】:2018-06-07 05:27:09
【问题描述】:
我见过下面的模式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 这样的用法还有可能吗?
如果没有,阻止它的原因是什么?
【问题讨论】:
-
在第一个示例中不安全地使用
t需要事先运行一堆与簿记相关的检查吗? -
@StoryTeller 它确实需要一点谨慎,但没有什么是 SBRM 无法处理的。通常,对象实际上的作用域是
main,它只是为了避免在静态初始化/销毁期间做太多事情,同时保持全局访问点。 -
我很确定
T &t = reinterpret_cast<T &>(storage);表现出未定义的行为 - 或者更确切地说,t的后续使用会。正确的做法是T& t = *new(&storage) T;。这基本上等同于在std::optional中设置值。所以最后,它是一个六个,另一个六个。 -
@IgorTandetnik 这应该等效于指针杂耍there,这显然很好。
-
来自那个问题:“我使用placement new来创建对象”
标签: c++ language-lawyer design-rationale stdoptional