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

为何std::optional<T>离开作用域时会触发T的两次析构?

替换无父QObject裸指针:std::unique_ptr vs std::optional 析构疑问

背景需求

我需要替换一段处理无父QObject对象的裸指针逻辑,这类对象被当作可选对象使用,原有代码如下:

if(m_file)
   delete m_file;
m_file = new QFile(...);

std::unique_ptr和std::optional看起来都符合替代需求,但测试时发现std::optional的输出存在疑似异常的行为——T的析构函数似乎被调用了两次,因此担心会引发资源释放问题,目前更倾向于使用std::unique_ptr。

测试代码及输出

测试代码

struct Loud
{
    Loud(std::string name) : m_name{ name } { print("Creating"); }
    Loud(const Loud& other) : m_name{ other.m_name } { print("Copying"); }
    Loud(Loud&& other) : m_name{ other.m_name }{ print("Moving"); }
    ~Loud() { print("Destroying"); }
    Loud& operator=(const Loud& other){ this->m_name = other.m_name; print("Copy="); return *this;}
    Loud& operator=(Loud&& other){ this->m_name = other.m_name; print("Move="); return *this;}

    std::string m_name;
    void print(std::string operation) { std::cout << operation << " " << m_name << "\n"; }
};

void optionalTest()
{
    std::optional<Loud> opt;
    opt = Loud("opt 1");
    opt = Loud("opt 2");
}

void uniqueTest()
{
    std::unique_ptr<Loud> unique;
    unique = std::make_unique<Loud>("unique 1");
    unique =  std::make_unique<Loud>("unique 2");
}

int main()
{
    optionalTest();
    std::cout << "\n";
    uniqueTest();
}

初始输出

Creating opt 1
Moving opt 1
Destroying opt 1
Creating opt 2
Move= opt 2
Destroying opt 2
Destroying opt 2    <-- 为何会这样?

Creating unique 1
Creating unique 2
Destroying unique 1
Destroying unique 2

补充验证

后来修改了移动赋值运算符,在移动操作后修改other.m_name以标记被移动的对象,输出结果清晰显示:只有最后一次析构是std::optional<Loud>对象自身销毁,其余析构均来自临时对象。

修改后的移动赋值运算符

Loud& operator=(Loud&& other){ 
    this->m_name = other.m_name; 
    other.m_name += " (mvd from)";
    print("Move="); 
    return *this;
}

修改后输出

Creating opt 1
Moving opt 1
Destroying opt 1 (mvd from)
Creating opt 2
Move= opt 2
Destroying opt 2 (mvd from)
Destroying opt 2

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:53:02