为何对空std::optional调用operator*后emplace仍属于未定义行为?
为什么对空std::optional调用operator*后执行emplace仍属于未定义行为?
要搞懂这个问题,核心得抓住C++标准对std::optional<T>::operator*的硬性规定:当optional处于空状态(即has_value()返回false)时,调用operator*本身就是未定义行为——不管你有没有实际去访问解引用后得到的引用或指针。
看你给出的代码:
std::optional<int> opt_val; auto p_val = &(*opt_val); // 这里已经触发未定义行为 opt_val.emplace(0); // do something with p_val
第一行&(*opt_val)里的*opt_val,因为此时opt_val是空的,直接违反了operator*的前置条件(标准要求调用operator*前必须确保has_value()为true)。这种违反前置条件的函数调用,会直接让程序进入未定义状态,后续的emplace操作完全无法挽回——未定义行为一旦发生,整个程序的逻辑就不受标准约束了:编译器可能优化掉后续所有代码,可能产生随机的内存访问,甚至直接导致程序崩溃。
很多人容易陷入一个误区:觉得“只要不访问解引用后的内容就没事”,但标准里对operator*的要求是调用这个操作符的前提就是optional必须有值,空状态下调用它本身就是非法的,和你后续用不用返回的指针没有关系。
至于emplace的作用,它确实会在optional内部构造对象,把它从空状态转为有值状态,但这已经是在未定义行为发生之后的操作了。前面的&(*opt_val)已经破坏了程序的合法性,后续任何操作的结果都是不可预测的。
如果想要安全地获取optional内部对象的指针,正确的做法是先确保optional有值,再进行解引用:
std::optional<int> opt_val; opt_val.emplace(0); // 先构造对象,让optional进入有值状态 auto p_val = &(*opt_val); // 此时调用operator*合法 // do something with p_val
内容的提问来源于stack exchange,提问作者Adel M.
相关产品推荐
相关产品推荐

