我的 C++ 代码看起来(简化)如下:
#include <unistd.h>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
std::thread the_thread;
void my_thread_func(const 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();
}
(在编译器资源管理器上:https://godbolt.org/z/9GYTf7orz)
当我运行此代码时
clang-tidy --checks=performance-unnecessary-value-param
时,它会发出警告:
<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) {
但我的理解是,将
string_ptr
作为 const 引用传递给 my_thread_func()
是不正确的,因为这样线程将拥有对 start_thread()
本地对象的引用,并且该对象在线程运行时被销毁。
我的问题:
void my_thread_func(const std::shared_ptr<std::string>& string_ptr)
是否正确(且推荐),还是会出现错误?我的经验是 clang-tidy 通常是正确的:-) 这就是为什么我对这里的警告感到困惑。
clang-tidy 警告假设一个单线程上下文:对函数的普通调用
int get(std::shared_ptr<int> p,std::binary_semaphore &s) {
s.acquire();
return *p;
}
可能非常需要
std::shared_ptr
参数(对象,而不是引用)来保持 int
存活足够长的时间以返回它。 (调用者可能从某个表中获取了对 std::shared_ptr
的引用,而不是为调用构建它,并且无论信号量发出什么信号,都可能在执行此操作后立即删除唯一的其他引用。)
另外,即使为线程调用的函数具有引用 parameter,它也不会是对
std::thread
构造函数的参数的引用:每个这样的参数都被复制到一个临时 T 中,其生命周期为线程,参考文献是T。 (正如评论中提到的,您可以使用 std::ref
生成 std::reference_wrapper
,它可以转换回对原始参数的引用。)这意味着您可能根本不需要 std::shared_ptr
:您可以只构造对象作为参数,它将被移动到T。