视觉工作室实现“移动语义”和“右值引用” [英] visual studio implementation of "move semantics" and "rvalue reference"

查看:81
本文介绍了视觉工作室实现“移动语义”和“右值引用”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了关于c ++ 11并发(第3部分)和以下代码的Youtube视频,它编译并在视频中生成正确的结果。

I came across a Youtube video on c++11 concurrency (part 3) and the following code, which compiles and generates correct result in the video.

但是,我使用Visual Studio 2012时遇到了这个代码的编译错误。编译器提出了 toSin(list< double> &&&)。如果我将参数类型更改为 list< double>& ,编译的代码。

However, I got a compile error of this code using Visual Studio 2012. The compiler complains about the argument type of toSin(list<double>&&). If I change the argument type to list<double>&, the code compiled.

我的问题是 _tmain()中 move(list) ,是一个右值引用还是只是一个引用?

My question is what is returned from move(list) in the _tmain(), is it a rvalue reference or just a reference?

#include "stdafx.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <list>
#include <algorithm>
using namespace std;

void toSin(list<double>&& list)
{
    //this_thread::sleep_for(chrono::seconds(1));
    for_each(list.begin(), list.end(), [](double & x)
    {
        x = sin(x);
    });

    for_each(list.begin(), list.end(), [](double & x)
    {
        int count = static_cast<int>(10*x+10.5);
        for (int i=0; i<count; ++i)
        {
            cout.put('*');
        }
        cout << endl;
    });
}    

int _tmain(int argc, _TCHAR* argv[])
{
    list<double> list;

    const double pi = 3.1415926;
    const double epsilon = 0.00000001;
    for (double x = 0.0; x<2*pi+epsilon; x+=pi/16)
    {
        list.push_back(x);
    }

    thread th(&toSin, /*std::ref(list)*/std::move(list));
    th.join();    

    return 0;
}


推荐答案

在MSVC2012。 (和快速检查,MSVC2013和MSVC2015)

This appears to be a bug in MSVC2012. (and on quick inspection, MSVC2013 and MSVC2015)

线程不直接使用完美转发,对于数据(临时的或非临时的),并且在生成的线程中使用它将极其容易出错和危险。

thread does not use perfect forwarding directly, as storing a reference to data (temporary or not) in the originating thread and using it in the spawned thread would be extremely error prone and dangerous.

而是将每个参数复制到 decay_t<?> 的内部数据。

Instead, it copies each argument into decay_t<?>'s internal data.

错误是当它调用worker函数时,该内部副本到您的过程。

The bug is that when it calls the worker function, it simply passes that internal copy to your procedure. Instead, it should move that internal data into the call.

这似乎不是在编译器版本19中修复,我认为是MSVC2015(没有双重检查),基于在这里编译你的代码

This does not seem to be fixed in compiler version 19, which I think is MSVC2015 (did not double check), based off compiling your code over here

这是由于标准的措辞(它应该调用一个 decay_t< F> decay_t< Ts> ... - 这意味着值的绑定,而不是Lvalue绑定)存储在线程中的本地数据将不会在调用您的过程之后再次使用(因此,逻辑上它应该被视为过期数据,而不是持久数据)。

This is both due to the wording of the standard (it is supposed to invoke a decay_t<F> with decay_t<Ts>... -- which means rvalue binding, not lvalue binding), and because the local data stored in the thread will never be used again after the invocation of your procedure (so logically it should be treated as expiring data, not persistent data).

一个工作:

template<class F>
struct thread_rvalue_fix_wrapper {
  F f;
  template<class...Args>
  auto operator()(Args&...args)
  -> typename std::result_of<F(Args...)>::type
  {
      return std::move(f)( std::move(args)... );
  }
};
template<class F>
thread_rvalue_fix_wrapper< typename std::decay<F>::type >
thread_rvalue_fix( F&& f ) { return {std::forward<F>(f)}; }

然后

thread th(thread_rvalue_fix(&toSin), /*std::ref(list)*/std::move(list));

应该可以正常工作。 (测试在MSVC2015在线编译器链接上面)根据个人经验,它也应该在MSVC2013工作。我不知道MSVC2012。

should work. (tested in MSVC2015 online compiler linked above) Based off personal experience, it should also work in MSVC2013. I don't know about MSVC2012.

这篇关于视觉工作室实现“移动语义”和“右值引用”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆