You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用std::variant与std::monostate时结构体为何被析构两次?

std::variant中A类构造1次、析构2次的原因解析

先看你的代码:

#include <iostream>
#include <variant>

struct A
{
    A() { std::cout << "Constructing A\n"; }
    ~A() { std::cout << "Destructing A\n"; }
};


struct B
{
    B() { std::cout << "Constructing B\n"; }
    ~B() { std::cout << "Destructing B\n"; }
};


int main()
{
    std::variant<std::monostate, A, B> ab;
    ab = A();
}

运行输出:

Constructing A
Destructing A
Destructing A

原因拆解

两次析构对应两个不同的A对象,只是第二个A对象的构造日志被隐藏了——它是通过编译器默认生成的移动/拷贝构造函数创建的,而你没给A定义带输出的移动/拷贝构造,所以看不到对应的构造信息。具体步骤:

  1. variant初始化阶段:std::variant<std::monostate, A, B> ab; 默认激活std::monostate,不会触发A或B的构造。
  2. 赋值语句执行阶段:
    • 首先创建临时A对象:A()触发构造函数,输出Constructing A。
    • std::variant的赋值操作会把这个临时A对象移动(或拷贝)到自身内部,替换原来的monostate。因为编译器生成的默认移动/拷贝构造函数没有输出语句,所以这一步看不到构造日志,但确实创建了第二个A对象。
    • 临时A对象在赋值语句执行完成后立即被销毁,触发第一次析构,输出Destructing A。
  3. 程序结束阶段:main函数执行完毕,variant对象ab被销毁,其内部存储的A对象也随之析构,触发第二次析构,输出Destructing A。

验证方法

给A添加移动构造函数并加上输出:

A(A&&) { std::cout << "Moving A\n"; }

重新运行代码,输出会变成:

Constructing A
Moving A
Destructing A
Destructing A

这样就能清晰看到第二个A对象是通过移动构造创建的,也就解释了两次析构的来源。

内容的提问来源于stack exchange,提问作者Chiel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 08:47:09