传递shared_ptr给线程函数时如何规避clang-tidy警告?
简化后的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对象不会被销毁,逻辑是正确的。 - 最优写法有两种:
- 保持值传递:这是最安全的写法,通过拷贝明确延长生命周期,语义清晰,不易出错;
- 用
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
相关产品推荐
相关产品推荐

