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

使用std::thread时智能指针引发的编译错误原因咨询

C++ std::thread编译错误及解决方案解析

问题背景

开发使用std::thread的C++程序时遇到编译错误,自行修改代码后问题解决,但对原因存在疑问,以下是简化后的代码及问题说明:

初始报错代码

void main_func()
{
    std::map<int, int>* requests_map = {};
    
    SortInput(requests_map);    // 该函数会修改requests_map的值,确认不会引发编译错误
    Execute(requests_map, input_tensors);   // input_tensors来自其他地方,确认不会引发编译错误
}

// Execute函数实现(简化版):
void Execute(std::map<int, int>* requests_info, 
             std::shared_ptr<std::unordered_map<std::string, Tensor>> input_tensors)
{
    
    // 在此创建智能指针
    auto requests_info_ptr = std::make_shared<std::map<int, int>>(*requests_info);
    
    // 创建线程执行forward函数
    my_thread = std::thread(ThreadForward, &input_tensors, &requests_info_ptr);

    my_thread.join();
}

// ThreadForward函数实现(简化版):
int ThreadForward(std::shared_ptr<std::unordered_map<std::string, Tensor>>* input_tensors,
                  std::shared_ptr<std::map<int, int>>* requests_info)
{
    // 处理逻辑
}

编译报错信息:

error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
  120 |           typename decay<_Args>::type...>::value,
      |                                            ^~~~~

修改后可行的代码

将智能指针的初始化移到Execute函数外,修改后代码如下:

void main_func()
{
    // 在此初始化智能指针
    auto requests_map = std::make_shared<std::map<int, int>>();
    
    SortInput(requests_map);    
    
    Execute(requests_map, input_tensors);   // input_tensors来自其他地方,确认不会引发编译错误
}

// Execute函数实现(简化版):
void Execute(std::shared_ptr<std::map<int, int>> requests_info, 
             std::shared_ptr<std::unordered_map<std::string, Tensor>> input_tensors)
{
    
    // 无需额外操作,已通过参数获取shared_ptr
    
    // 创建线程执行forward函数,直接传入指针
    my_thread = std::thread(ThreadForward, &input_tensors, &requests_info);

    my_thread.join();
}

// ThreadForward函数实现(简化版):
int ThreadForward(std::shared_ptr<std::unordered_map<std::string, Tensor>>* input_tensors,
                  std::shared_ptr<std::map<int, int>>* requests_info)
{
    // 处理逻辑
}

修改后编译通过,问题解决。

疑问解答

1. 为何初始写法会触发静态断言错误?

std::thread构造时会对传入参数做右值转换(通过std::decay处理),并将处理后的参数存储到线程内部存储区。初始写法中,requests_info_ptr是Execute内的局部变量,传入的&requests_info_ptr指向的是即将随函数执行结束销毁的对象——C++标准通过静态断言禁止这种明显的悬空指针风险。

同时,input_tensors是Execute的函数参数,传入&input_tensors本质是指向函数参数的指针,虽然参数生命周期在Execute内,但std::thread的参数检查逻辑会判定这种指向局部对象(含函数参数)的指针存在生命周期不匹配风险,最终触发断言。

2. 为何将智能指针初始化移到外部就能解决问题?

修改后,requests_map是main_func的局部变量,Execute接收的是shared_ptr的副本,requests_info作为Execute的参数,其生命周期覆盖整个Execute执行过程(包括my_thread.join()等待线程结束的阶段)。此时传入&requests_info,指向的对象在线程执行期间始终有效,编译器的静态断言检查可以确认安全性,因此不会报错。

3. 原始写法中使用裸指针转智能指针的方式存在什么问题?

原始写法存在三个核心问题:

  • 冗余拷贝:std::make_shared<std::map<int, int>>(*requests_info)会创建原map的完整拷贝,而非共享原对象所有权,带来不必要的内存和时间开销。
  • 生命周期失控:原requests_map是裸指针,若main_func未正确释放会引发内存泄漏;若提前释放,Execute中拷贝原map时会出现悬空指针访问。
  • 逻辑偏离预期:SortInput修改的是原map,但线程处理的是拷贝后的新map,两者数据完全独立,违背了“共享请求信息”的业务逻辑预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:35:29