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

如何用不可复制不可移动类的成员函数启动线程?VS2015编译报错疑问

问题1:如何使用不可复制且不可移动类的对象成员函数启动线程?

这个问题挺常见的——当类因为包含std::mutex、std::unique_ptr这类不可复制移动的成员,导致自身也不可复制、不可移动时,直接把对象传递给std::thread构造函数肯定会失败,因为默认情况下std::thread会尝试复制或移动对象。这里有两种可靠的解决办法:

  • 传递对象的指针:直接把对象的地址传给std::thread,这样不需要复制或移动对象,线程会通过指针调用成员函数。示例代码如下:

    class NonCopyableNonMovable {
    public:
        NonCopyableNonMovable() = default;
        // 显式删除复制、移动构造和赋值运算符
        NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
        NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
        NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
        NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
    
        void do_work() {
            // 线程执行的逻辑
        }
    };
    
    int main() {
        NonCopyableNonMovable obj;
        std::thread t(&NonCopyableNonMovable::do_work, &obj); // 传递对象指针
        t.join();
        return 0;
    }
    
  • 用std::ref传递对象的引用:通过std::reference_wrapper(std::ref会帮你生成这个包装器)让std::thread以引用方式持有对象,避免复制/移动。一定要注意:必须保证对象的生命周期长于线程,否则会出现悬空引用,导致未定义行为。示例代码:

    #include <functional> // 必须包含这个头文件才能用std::ref
    
    // 类定义同上...
    
    int main() {
        NonCopyableNonMovable obj;
        std::thread t(&NonCopyableNonMovable::do_work, std::ref(obj)); // 传递引用
        t.join();
        return 0;
    }
    
问题2:代码在Visual Studio 2015中无法编译,但在ideone上可正常运行的原因?

先看你给出的代码:

class FooMutex { std::mutex stm; public: void foo() {} };
int main() { FooMutex o; std::thread t1(&FooMutex::foo, o); }

核心原因

  1. FooMutex的可复制性问题:std::mutex是C++标准中明确规定的不可复制、不可移动类型,所以当你的FooMutex类包含std::mutex成员时,编译器会自动删除FooMutex的默认复制构造函数和移动构造函数——也就是说,FooMutex对象是不能被复制或移动的。

  2. 标准库实现的版本差异:

    • Visual Studio 2015的缺陷:VS2015附带的标准库实现存在不足,当你把o(左值对象)传递给std::thread构造函数,配合成员函数指针使用时,它错误地尝试复制o对象。但因为FooMutex不可复制,所以触发了C2664的编译错误(错误信息里的参数匹配失败本质就是复制操作无法完成)。
    • ideone的编译器(通常是GCC较新版本):更新的GCC标准库完全遵循了C++11及之后的标准,正确处理了这种场景——它不会尝试复制不可复制的对象,而是通过引用传递的方式(或者其他符合标准的机制)来构造线程,所以代码可以正常编译运行。

修复VS2015的编译错误

只需要调整传递o的方式,和问题1的解决思路一致:

// 方式1:传递对象指针
std::thread t1(&FooMutex::foo, &o);
// 方式2:用std::ref传递引用(记得包含<functional>头文件)
std::thread t1(&FooMutex::foo, std::ref(o));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:10:16