std::for_each处理不可拷贝对象为何编译报错?VS2015下std::thread问题
你的误解点分析及问题解决
首先得说,你对std::for_each的核心规则理解是对的:它确实不会拷贝容器中的元素,哪怕是并行版本的std::for_each,也不会像其他并行算法那样(比如std::transform)为了并行处理而拷贝元素到临时缓冲区。所以处理存放不可拷贝对象的容器本身是没问题的。
那问题出在哪呢?看你写的lambda表达式:
[threads](std::thread & t) {t.join(); }
这里的[threads]是值捕获,意味着编译器会把外部的threads这个std::vector<std::thread>完整拷贝一份,作为lambda对象的成员变量。而std::thread的拷贝构造函数是被显式删除的(因为线程是不可拷贝的资源),所以当尝试拷贝整个vector时,每个std::thread元素的拷贝都会触发C2280错误——这和std::for_each半毛钱关系都没有!
怎么解决?
其实你的lambda里根本没用到捕获的threads变量啊!你只需要操作参数t就行,所以直接改成空捕获就好:
std::for_each(threads.begin(), threads.end(), [](std::thread & t) {t.join(); });
如果之后你确实需要捕获threads,那可以根据场景选:
- 用引用捕获
[&threads],这样不会拷贝整个vector,只是引用外部变量; - 如果你想转移vector的所有权(C++14及以上支持),用移动捕获
[threads = std::move(threads)],这样只会触发std::thread的移动构造,而移动是允许的。
总结你的误解
你错误地把lambda捕获导致的拷贝行为,归罪到了std::for_each对容器元素的处理上。std::for_each全程只是迭代访问容器的元素(这里是通过引用访问t),没有做任何元素拷贝操作,锅完全在lambda的捕获方式上。
内容的提问来源于stack exchange,提问作者TonySalimi
相关产品推荐
相关产品推荐

