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

如何用模板构造函数和Lambda封装std::thread?为何func()中数据重复?

问题解答

一、为何func()中的数据会重复?

问题出在Thread构造函数的Lambda捕获逻辑上:

internal_{ [func = std::forward<Function>(f), &args...]() {
    func(args...);
} }

这里用&args...引用捕获构造函数的参数,但构造函数的Args&&...args是转发引用,这些参数的生命周期仅存在于构造函数执行期间。当构造函数执行完毕返回后,Lambda中捕获的引用就变成了悬空引用。

在main函数的循环中,每次创建Thread对象时,构造函数的参数(比如&data[i])会被存储为临时引用,循环进入下一次迭代时,这些临时引用的内存可能被复用,导致后续线程执行时,访问的是被覆盖后的指针值,最终出现多个线程拿到相同Data地址和id的情况。

二、如何正确用模板构造函数和Lambda封装std::thread?

核心是避免悬空引用,需要将参数值捕获或完美转发到Lambda中,确保Lambda拥有参数的副本或所有权,以下是两种可行的修正方案:

方案1:用Tuple+std::apply处理参数(兼容C++17)

#include <memory>
#include <thread>
#include <unistd.h>
#include <vector>
#include <utility>
#include <tuple>

struct Data {
    int id;
};

class Thread {
public:
    template <class Function, class... Args>
    Thread(Function &&f, Args &&...args) noexcept
        : internal_{ 
            [func = std::forward<Function>(f), args = std::make_tuple(std::forward<Args>(args)...)]() {
                std::apply(func, std::move(args));
            } 
        }
    {
    }

    ~Thread() {
        if (internal_.joinable()) {
            internal_.join();
        }
    }

private:
    std::thread internal_;
};

void func(Data *data)
{
    printf("                in thread, data: %p, id: %d\n", data, data->id);
}

int main()
{
    static Data data[8];
    std::vector<std::unique_ptr<Thread>> threads;
    int i = 0;
    for (i = 0; i < 8; i++) {
        data[i].id = i;
        printf("out thread, data: %p\n", &data[i]);
        threads.emplace_back(std::make_unique<Thread>(func, &data[i]));
    }

    return 0;
}

方案2:直接展开参数值捕获(C++20及以上)

如果编译器支持C++20,可简化捕获逻辑:

template <class Function, class... Args>
Thread(Function &&f, Args &&...args) noexcept
    : internal_{ 
        [func = std::forward<Function>(f), ...args = std::forward<Args>(args)]() {
            func(args...);
        } 
    }
{
}

关键修正点:

  • 避免悬空引用:通过值捕获将参数的副本或移动后的所有权转移到Lambda中,确保线程执行时参数有效。
  • 线程生命周期管理:添加析构函数join线程,避免程序提前退出导致线程未完成。
  • 内存安全:用std::unique_ptr管理Thread对象,避免手动new/delete引发的内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:55:18