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

std::thread执行结束后意外调用MustP3DPlugin析构函数原因求解

现象原因解释

核心原因是std::thread的参数传递默认采用值传递语义,你看到的析构调用是线程内部存储的参数副本被销毁,不是原始MustP3DPlugin对象被析构。

两种传参方式的差异

  • 调用std::thread(createMemoryLeak, *this)的场景
    线程函数createMemoryLeak形参虽然是引用类型,但std::thread构造时不会直接把原始的*this绑定到引用上,会先对*this做拷贝构造生成一个临时副本存储在线程内部,再把这个副本绑定到函数的引用形参。当线程执行结束后,这个内部存储的临时副本会被销毁,因此会触发~MustP3DPlugin()调用,此时被析构的是拷贝生成的临时对象,你在main里定义的原始plugin对象还处于生命周期中。
  • 调用std::thread(createNoMemoryLeak, this)的场景
    此时传入的是对象指针,std::thread只会复制指针的数值,不会复制指针指向的MustP3DPlugin对象。线程执行结束后只会销毁内部存储的指针副本,不会触发对象的析构函数,因此不会看到弹框。

验证方案

你可以给MustP3DPlugin类添加拷贝构造函数打印日志,就能清晰看到临时副本的创建过程:

MustP3DPlugin(const MustP3DPlugin& other) {
    MessageBox(nullptr, TEXT("拷贝构造函数被调用"), TEXT("debug text"), MB_OK);
}

解决方案(如果不需要拷贝对象)

如果希望线程直接引用原始对象,不需要生成副本,需要用std::ref包裹要传递的引用参数:

std::thread memoryLeakThread = std::thread(createMemoryLeak, std::ref(*this));

这种情况下std::thread内部会存储引用包装器,不会生成对象副本,线程结束也不会触发额外的析构调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:54:03