Why can't I use the link in std :: future options

Why did the following code ( in Ideone ) give me an error?

#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; } 

Output:

 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...>) ^ 

However, if I change bool& to bool in the parameter list, it compiles successfully .

Why?

+5
source share
2 answers

Like std::thread , std::asyc passes parameters by value to a "function". If you have a function that takes a link, you need to wrap the variable that you pass into asyc with std::ref , for example

 #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; } 

Living example

If the function accepts const & then you need to use std::cref .

+12
source

Think about what would happen if he bound the bar by reference.

Then, every time you called std::async , each value you pass should last until the asynchronization is complete.

This will be a recipe for accidental memory corruption. Thus, std::async instead copies by default everything that you pass to it.

Then it runs the task on a copy of your input.

Being smart, it tells the code you call that the value is not constant by moving it to the code. And lvalue links cannot bind to relocated values.

You can override this behavior using std::reference_wrapper . async understands reference_wrapper , and it automatically saves a link to these values ​​and passes them by reference to the called code.

An easy way to create a reference_wrapper is to call 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; 

and it just works.

This β€œonly pass by reference explicitly” is a security function of the binding operation as an operation; because linked execution can persist outside the current state, it requires callers to only link explicitly, thereby reducing the chance of inadvertent links to dangling links.

+8
source

Source: https://habr.com/ru/post/1260996/


All Articles