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

传递shared_ptr给线程函数时如何规避clang-tidy警告?

关于clang-tidy警告与shared_ptr线程传递的疑问

简化后的C++代码

#include <unistd.h>

#include <iostream>
#include <memory>
#include <string>
#include <thread>

std::thread the_thread;

void my_thread_func(std::shared_ptr<std::string> string_ptr) {
    std::cout << "at thread begin: " << *string_ptr << std::endl;
    sleep(1);
    std::cout << "at thread finish: " << *string_ptr << std::endl;
}

void start_thread() {
    auto local_string_ptr = std::make_shared<std::string>("foobar");
    the_thread = std::thread(&my_thread_func, local_string_ptr);
}

int main(int, char**) {
    start_thread();
    sleep(2);
    the_thread.join();
}

clang-tidy警告信息

<source>:10:50: warning: the parameter 'string_ptr' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
   10 | void my_thread_func(std::shared_ptr<std::string> string_ptr) {

疑问点

  • 使用void my_thread_func(const std::shared_ptr<std::string>& string_ptr)是否正确且推荐?会不会出错?
  • 该clang-tidy警告是否正确,还是误报?
  • 我的代码是否存在错误/不够优雅,从而引发此问题?最优写法是什么?

解答

1. 传递const引用是否正确?

绝对不推荐,大概率会导致未定义行为。
当把local_string_ptr传给std::thread构造函数时,如果线程函数接收的是const引用:

  • 若不用std::ref包装参数,std::thread会生成临时shared_ptr副本,这个临时对象在线程构造完成后就销毁,线程内的引用会变成悬空引用;
  • 若用std::ref(local_string_ptr),线程持有的是start_thread()局部shared_ptr的引用,start_thread()执行完毕后局部对象销毁,线程运行时访问该引用会触发未定义行为(如崩溃、输出乱码)。

2. clang-tidy警告是误报吗?

属于场景化误报。
performance-unnecessary-value-param检查仅关注函数参数的使用逻辑:它看到函数内仅将string_ptr作为const引用使用(无修改操作),因此判定拷贝多余。但它未考虑到该函数是线程入口函数的特殊场景——此处的拷贝是为了延长shared_ptr的生命周期,保证线程运行期间关联的string对象不被销毁。这个检查的优化建议仅适用于通用场景,不适用于线程传递shared_ptr的情况。

3. 原代码的问题与最优写法

原代码本身没有错误,但可以更优雅:

  • 原代码中std::thread构造时拷贝local_string_ptr,会增加shared_ptr的引用计数,保证线程运行期间string对象不会被销毁,逻辑是正确的。
  • 最优写法有两种:
    1. 保持值传递:这是最安全的写法,通过拷贝明确延长生命周期,语义清晰,不易出错;
    2. 用std::move转移所有权:减少一次引用计数的增减操作,效率略高,同时语义明确,将shared_ptr的所有权转移给线程:
      void start_thread() {
          auto local_string_ptr = std::make_shared<std::string>("foobar");
          the_thread = std::thread(&my_thread_func, std::move(local_string_ptr));
      }
      

若想让clang-tidy忽略该警告,可在函数前添加注释:

// NOLINTNEXTLINE(performance-unnecessary-value-param)
void my_thread_func(std::shared_ptr<std::string> string_ptr) {
    // ...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:15:01