构造variant期间观测其状态,哪个C++标准库实现符合规范?
问题分析结论
libc和MSVC的实现符合C标准要求,GCC 11的libstdc++实现不符合标准。
核心原因
你对valueless_by_exception()的语义和emplace的执行流程存在误解:
std::variant::emplace切换类型的标准执行顺序为:- 销毁当前variant持有的旧值(示例中初始持有的
std::monostate会被先销毁) - 在variant的内部存储中构造新类型实例(即foo对象)
- 新对象构造完成后,variant标记为持有对应类型的有效值
- 销毁当前variant持有的旧值(示例中初始持有的
- 你在foo的构造函数中调用
var.valueless_by_exception()时,正处于旧值已销毁、新对象未构造完成的过渡阶段,此时variant确实没有持有任何有效值。 - C++标准明确规定
valueless_by_exception()的返回规则为:当且仅当variant当前不持有任何值时返回true。你引用的标准条款仅说明「variant永久进入无值状态的唯一触发场景是emplace/赋值过程中抛出异常」,并没有禁止过渡阶段临时处于无值状态。 - GCC libstdc++的实现属于非标准扩展,它在销毁旧值之前就先标记了新类型的状态,所以过渡阶段
valueless_by_exception()也会返回false,这并不符合标准的语义要求。
测试代码
#include <variant> #include <cassert> struct foo { foo() noexcept; foo(const foo&) noexcept = default; foo(foo&&) noexcept = default; foo& operator=(const foo&) noexcept = default; foo& operator=(foo&&) noexcept = default; }; std::variant<std::monostate, foo> var; foo::foo() noexcept { assert(!var.valueless_by_exception()); }; int main() { var.emplace<foo>(); }
内容的提问来源于stack exchange,提问作者Jean-Michaël Celerier
相关产品推荐
相关产品推荐

