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

含std::thread与std::mutex的类是否需删除拷贝构造及赋值运算符?

你必须删除这个类的拷贝构造函数和赋值运算符(而且编译器其实已经帮你做了一部分)

首先得纠正一个关键误解:你的类根本无法使用默认拷贝构造函数,因为std::thread和std::mutex都是非可拷贝类型——它们的拷贝构造函数和赋值运算符都被标准库显式删除了。当你尝试让编译器生成默认的拷贝构造/赋值逻辑时,它会直接抛出编译错误,因为无法完成这两个成员变量的拷贝操作。

那为什么还要手动删除它们?这是一种代码可读性和意图明确性的最佳实践:明确告诉其他开发者(包括未来的你),这个类的对象是不能被拷贝或赋值的,避免有人尝试编写拷贝代码时,困惑于模糊的编译错误信息。

接下来聊聊你推理中的核心问题:你认为“默认拷贝会复制整个状态所以没问题”,但这个假设从根上就不成立:

  • 对于std::thread:拷贝线程对象没有任何合理语义——你是想复制一个线程的执行状态?还是让两个线程对象指向同一个底层线程?标准库直接禁止了这种操作,因为无论哪种语义都会带来致命的线程安全风险(比如两个对象的析构函数都去join同一个线程,会触发未定义行为)。
  • 对于std::mutex:拷贝互斥锁完全没有意义。原对象的线程锁定的是原互斥锁,拷贝后的对象拥有一个全新的互斥锁,这会让你的线程同步逻辑彻底失效——不同线程操作同一个共享资源时,可能锁定的是不同的互斥锁,完全起不到同步作用。

回到你的代码示例,正确的做法是显式删除拷贝构造和赋值运算符:

class A : B {
    std::thread t;
    std::mutex m;
public:
    A() : B() {}
    virtual ~A() { if (t.joinable()) t.join(); }

    // 明确禁止拷贝和赋值
    A(const A&) = delete;
    A& operator=(const A&) = delete;

    virtual void Method() {
        t = std::thread([this] {
            std::lock_guard<std::mutex> lck(m);
            // ... 处理逻辑
        });
    }
    // 其他会锁定mutex m的方法
};

如果你的业务场景需要转移对象的所有权(比如把A的对象从一个容器移动到另一个),那你需要注意:std::mutex也是不可移动的,所以默认的移动构造/赋值也会被编译器删除。这种情况下,你可能需要用std::unique_ptr<std::mutex>来包装互斥锁,让它支持移动,同时手动实现移动构造/赋值逻辑,确保线程所有权的正确转移(比如移动std::thread时,原对象的线程会变为不可joinable状态)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:32:18