【问题标题】: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&lt;double,std::allocator&lt;_Ty&gt;&gt; &amp;&amp;)' : 无法将参数 1 从 'std::list&lt;double,std::allocator&lt;_Ty&gt;&gt;' 转换为 'std::list&lt;double,std::allocator&lt;_Ty&gt;&gt; &amp;&amp;'

【问题讨论】:

  • 无法复制。您使用的是哪个版本的视觉工作室?请注意,我添加了一堆缺失的标题。
  • std::thread th(toSin, std::move(list)); 行暗示你不应该在list 上迭代超过那个点,因为它已经被移走了。但是您尝试在下一行对其进行迭代。
  • Visual Studio 2013
  • 2013 缺少很多 C++ 11 支持。在 2015 年编译,但不应该按照您想要的方式运行。看看能不能升级。还要注意@FrançoisAndrieux 的警告。
  • 除了 FrançoisAndrieux 评论,如果您希望使用相同的列表,您将拥有 UB,因为并发访问不同步(互斥,...)。

标签: c++ c++11 stl


【解决方案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::thread{toSin, 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进不去,坑都填完看不到升级的意义,所以没副本试试。
猜你喜欢
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
  • 2016-12-05
  • 2019-07-09
  • 2014-02-16
  • 2018-02-25
  • 2018-11-08
相关资源
最近更新 更多