You need to enable JavaScript to run this app. C++ 创建线程时传入this与std::ref(*this)有什么区别?
优惠活动
大模型
产品
解决方案
定价
更多

C++ 创建线程时传入this与std::ref(*this)有什么区别?

std::thread 绑定类成员函数时 this 与 std::ref(*this) 的差异

核心规则

std::thread 构造时会对所有传入的实参执行按值的移动/拷贝,默认不会保留原始实参的引用语义——只有当传入的实参本身是指针、或是std::reference_wrapper这类引用包装类型时,最终才能在新线程中操作原始的外部对象。

两种写法的共性

在「类的成员函数内部创建线程、绑定当前类的非静态成员函数」的典型场景下,两种写法的最终运行行为几乎没有区别:

  • 传入this时,std::thread拷贝的是裸指针本身(即当前类实例的内存地址),全程不会触发类对象实体的拷贝,新线程拿到的是和主线程指向同一个实例的指针。
  • 传入std::ref(*this)时,std::ref会生成一个内部持有当前实例引用的轻量代理对象,std::thread拷贝的也是这个代理对象(本质是存储了指向当前实例的指针),同样全程不会触发类对象实体的拷贝,新线程拿到的依然是对原始实例的访问权限。
  • 两种写法都不会持有类对象的所有权,也不会延长对象的生命周期:如果将线程detach后,对象先于线程执行完成被析构,两种写法都会触发悬垂访问的未定义行为,这部分表现完全一致。

实际存在的细节差异

  • 传递语义的可读性差异
    • std::ref(*this)是显式标记「线程将直接操作原对象,不生成对象副本」,其他维护代码的人可以一眼看懂传递的是引用语义,不会因为不熟悉std::thread的参数传递规则,误判为传值拷贝。
    • 传裸this的写法是C++中绑定成员函数的常规操作,但对不熟悉标准库参数传递规则的开发者来说,传递语义的辨识度更低。
  • 类型适配的灵活性差异
    当要绑定的成员函数带有复杂的const/volatile修饰时:
    • 传裸this的参数类型完全由当前调用上下文决定(比如在const成员函数中拿到的this是const A*类型),如果成员函数的cv修饰和当前指针类型不兼容,会直接触发编译错误,很多时候需要手动加const_cast做类型转换。
    • std::ref(*this)生成的引用包装类型会严格匹配当前*this的cv属性,只要原始对象的cv修饰和成员函数要求匹配,包装类型就可以通过隐式转换自动生成对应的this指针,减少手动类型转换的代码量。
  • 误用风险的差异
    两种写法从根源上都规避了std::thread按值拷贝类对象的常见坑:如果混淆写法,把带std::ref的std::ref(*this)换成不带ref的*this,就会触发类对象的深/浅值拷贝,让线程操作一个和主线程完全独立的副本,极易引发逻辑错误。而传this的写法因为传递的是指针,从类型层面就不可能触发整个对象的拷贝,不存在这类误用空间。

注:两种写法的传递目标完全一致,都不会产生类对象的实体拷贝,不存在「传this是值传递、传std::ref是引用传递」的本质区别,差异仅集中在可读性、适配性和误用风险层面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 02:06:04