使用std::thread调用模板函数traverse时编译报错求助
嘿,我来帮你搞定这段C++代码的问题~
先说说编译错误的核心原因
你遇到的编译问题主要来自两个关键点:
- 引用传递的冲突:你的
traverse函数的容器参数是非const左值引用,但std::thread创建时默认会把所有参数按值拷贝到线程内部。这就导致线程里的容器参数会绑定到一个临时的拷贝对象,而C++不允许非const引用绑定临时对象,直接触发了类型不匹配的错误。 - 主线程未等待子线程:哪怕编译通过,你的主线程会在子线程还没完成遍历赋值时就直接输出
outp,这会导致数据竞争,输出的大概率是未初始化的垃圾值,属于未定义行为。
修正后的完整代码
#include<iostream> #include<vector> #include<thread> #include<functional> using namespace std; template<typename Container, typename Functor, typename ResultContainer> void traverse(Container& container, Functor lambda, ResultContainer& out) { size_t ind = 0; // 用size_t更符合容器索引的标准类型 for(auto& elem : container) // 范围for循环比迭代器更简洁易读 { out[ind++] = lambda(elem); } } int main() { vector<int> inp; for(int i=0;i<1000;i++) inp.push_back(rand()%1000); // 用auto直接推导lambda类型,比std::function更高效 auto lambda = [](int a){return static_cast<float>(a*2.5);}; vector<float> outp(1000); // 用std::ref包装引用参数,告诉线程传递原对象的引用而非拷贝 // 模板参数可以让编译器自动推导,不用手动指定 thread t1(traverse, std::ref(inp), lambda, std::ref(outp)); // 必须等待子线程执行完毕,再访问处理后的outp t1.join(); size_t ind=0; for(auto i:outp) cout<<inp[ind++]<<" "<<i<<endl; }
关键修改点说明
std::ref()的使用:std::ref(inp)和std::ref(outp)明确告诉线程要传递原容器的引用,而非创建临时拷贝,完美解决了引用参数绑定的问题。t1.join()的添加:强制主线程等待子线程完成所有遍历赋值操作,彻底避免数据竞争和未定义行为。- lambda类型优化:用
auto推导lambda的原始类型,比std::function少了一层包装开销,效率更高。 - 索引类型规范:把
int索引改成size_t,和容器的size()返回类型匹配,避免潜在的类型不匹配警告。
如果你不需要修改输入容器,还可以把traverse的第一个参数改成const Container& container,符合C++的const正确性原则,让代码更安全。
内容的提问来源于stack exchange,提问作者Anil Gangwal BTech Electrical
相关产品推荐
相关产品推荐

