2016-12-08 5 views
5

次のコード(on Ideone)でエラーが示されるのはなぜですか?std :: futureのパラメータで参照を使用できない理由

#include <future> 
#include <iostream> 
#include <string> 

int main() 
{ 
    int foo = 0; 
    bool bar = false; 
    std::future<std::string> async_request = std::async(
     std::launch::async, 
     [=, &foo](bool& is_pumping_request) -> std::string { 
      return "str"; 
     }, 
     bar 
    ); 
    std::cout << async_request.get() << std::endl; 
} 

出力:

In file included from /usr/include/c++/5/future:38:0, 
       from prog.cpp:1: 
/usr/include/c++/5/functional: In instantiation of 'struct std::_Bind_simple<main()::<lambda(bool&)>(bool)>': 
/usr/include/c++/5/future:1709:67: required from 'std::future<typename std::result_of<_Functor(_ArgTypes ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = main()::<lambda(bool&)>; _Args = {bool&}; typename std::result_of<_Functor(_ArgTypes ...)>::type = std::basic_string<char>]' 
prog.cpp:15:2: required from here 
/usr/include/c++/5/functional:1505:61: error: no type named 'type' in 'class std::result_of<main()::<lambda(bool&)>(bool)>' 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
                  ^
/usr/include/c++/5/functional:1526:9: error: no type named 'type' in 'class std::result_of<main()::<lambda(bool&)>(bool)>' 
     _M_invoke(_Index_tuple<_Indices...>) 
     ^

しかし、私は、パラメータリストにbool&boolにを変更した場合、それcompiles successfully

なぜですか?

答えて

12

std::threadと同様に、std::asycは、パラメータを値で関数に渡します。あなたは、変数をラップする必要があるの参照を取る関数を持っている場合は、

#include <future> 
#include <iostream> 
#include <string> 

int main() 
{ 
    int foo = 0; 
    bool bar = false; 
    std::future<std::string> async_request = std::async(
     std::launch::async, 
     [=, &foo](bool& is_pumping_request) -> std::string { 
      return "str"; 
     }, 
     std::ref(bar) 
    ); 
    std::cout << async_request.get() << std::endl; 
} 

Live Example

ようstd::refasycに渡している機能がconst &を取るなら、あなたはstd::crefを使用する必要があります。

+0

'cref'は良い習慣ですが、' ref'と何も(コピーを渡して)何もしなくても動作します( "work"の定義のために) –

8

barを参照してバインドするとどうなるか考えてみましょう。

std::asyncを呼び出すたびに、渡されたすべての値は、非同期が完了するまで持続する必要があります。

これは、偶発的なメモリ破損のレシピになります。だから、std::asyncではなく、デフォルトであなたが渡したすべてのものをコピーします。

次に、入力のコピーに対してタスクを実行します。

スマートなので、コードに移動することによって値が非永続的であることを呼び出しているコードに伝えます。また、左辺値参照は移動元の値にバインドできません。

std::reference_wrapperを使用してこの動作を無効にすることができます。 asyncreference_wrapperを認識し、自動的にこれらの値への参照を格納し、呼び出されたコードに参照渡しを渡します。

reference_wrapperを簡単に作成する方法はstd::refです。

int foo = 0; 
bool bar = false; 
std::future<std::string> async_request = std::async(
    std::launch::async, 
    [=, &foo](bool& is_pumping_request) -> std::string { 
     return "str"; 
    }, 
    std::ref(bar) 
); 
std::cout << async_request.get() << std::endl; 

です。

この「参照によって明示的に渡す」は、バインディングのような操作の安全機能です。バインドされた実行は現在の状態を超えて持続する可能性があるため、呼び出し元は参照によって明示的にバインドされるだけで、意図しないダングリング参照が発生する可能性が少なくなります。

関連する問題