为啥 std::move 不能与 std::list 一起使用
Posted
技术标签:
【中文标题】为啥 std::move 不能与 std::list 一起使用【英文标题】:Why std::move is not working with std::list为什么 std::move 不能与 std::list 一起使用 【发布时间】:2017-07-04 17:29:59 【问题描述】:我无法编译下面的程序。
void toSin(std::list<double>&& list)
std::for_each(list.begin(), list.end(), [](double& x)
x = sin(x);
);
int main()
std::list<double> list;
const double pi = 3.141592;
const double epsilon = 0.0000001;
for (double x = 0.0; x < 2 * pi + epsilon; x = x + pi / 16)
list.push_back(x);
// Start thread
std::thread th(toSin, std::move(list));
th.join();
return 0;
我得到 > 错误 C2664: 'void (std::list<double,std::allocator<_Ty>> &&)
' : 无法将参数 1 从 'std::list<double,std::allocator<_Ty>>
' 转换为 'std::list<double,std::allocator<_Ty>> &&
'
【问题讨论】:
无法复制。您使用的是哪个版本的视觉工作室?请注意,我添加了一堆缺失的标题。std::thread th(toSin, std::move(list));
行暗示你不应该在list
上迭代超过那个点,因为它已经被移走了。但是您尝试在下一行对其进行迭代。
Visual Studio 2013
2013 缺少很多 C++ 11 支持。在 2015 年编译,但不应该按照您想要的方式运行。看看能不能升级。还要注意@FrançoisAndrieux 的警告。
除了 FrançoisAndrieux 评论,如果您希望使用相同的列表,您将拥有 UB,因为并发访问不同步(互斥,...)。
【参考方案1】:
我觉得你的编译器在这里错了。衰减(复制)的值类型应该可绑定到右值引用。
随便看看this quote from the documentation
3) 创建新的 std::thread 对象并将其与执行线程相关联。新的执行线程开始执行
std::invoke(decay_copy(std::forward<Function>(f)), decay_copy(std::forward<Args>(args))...);
基本上,您作为参数传递给std::thread
的构造函数的任何内容都将作为函数参数复制到该函数。
还要知道,如果你让它按值而不是按右值引用接受std::list
变量,你的函数将正常工作。更多详情请见Correct usage of rvalue references as parameters
如果您的意图是将变量的引用传递给线程函数,我通常使用 lambda
std::list<double> lst;
auto th = std::thread[&lst]()
toSin(lst);
;
但是你也可以使用std::ref
来达到同样的效果。我只是个人觉得 lambda 方法更清晰。
std::list<double> lst;
auto th = std::threadtoSin, std::ref(lst);
Also as correctly pointed out in the comments,您的代码中有一个竞争条件,您应该使用mutex
来阻止它,或者等待线程完成
auto th = std::thread[&lst]()
toSin(lst);
;
th.join();
// then iterate and print out
【讨论】:
更新了上面的代码,我只是想给工作线程一个唯一的内存以避免同步问题。 @NARESHKITTUR 但是,如果您这样做,您打算稍后在主线程中打印出列表吗? 没错,我将无法在主线程中使用列表。我将不得不在工作线程本身中处理/打印列表。所以为了解决这个问题,我应该通过互斥体的引用传递列表。 @NARESHKITTUR 正确,或者等待线程通过.join()
完成【参考方案2】:
我认为您可能会错过一些 #include
,该代码适用于 Visual Studio 2015
#include <algorithm>
#include <list>
#include <thread>
void toSin(std::list<double>&& list)
std::for_each(list.begin(), list.end(), [](double& x)
x = sin(x);
);
int main()
std::list<double> list;
const double pi = 3.141592;
const double epsilon = 0.0000001;
for (double x = 0.0; x < 2 * pi + epsilon; x = x + pi / 16)
list.push_back(x);
// Start thread
std::thread th(toSin, std::move(list));
th.join();
return 0;
【讨论】:
Visual Studio 2015 不是 Visual Studio 2013。2013 在其 c++11 支持方面存在巨大漏洞。它不编译的可能性很大。 2013进不去,坑都填完看不到升级的意义,所以没副本试试。以上是关于为啥 std::move 不能与 std::list 一起使用的主要内容,如果未能解决你的问题,请参考以下文章