为什么以下代码(on Ideone)会给我一个错误?
#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。
为什么?
答案 0 :(得分:13)
与std::thread
类似,std::asyc
将参数值传递给“函数”。如果你有一个带引用的函数,你需要将你传递给asyc
的变量包装成std::ref
,如
#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;
}
如果该功能需要const &
,那么您需要使用std::cref
。
答案 1 :(得分:8)
考虑如果它通过引用绑定bar
会发生什么。
然后,每当您调用std::async
时,您传递的每个值都必须持续到异步完成。
这将是意外记忆腐败的一个秘诀。因此,std::async
默认情况下会复制您传递给它的所有内容。
然后在输入的副本上运行任务。
聪明,它通过将代码移动到代码中来告诉您调用的代码,该值是非持久的。并且左值引用不能绑定到移动的值。
您可以使用std::reference_wrapper
覆盖此行为。 async
了解reference_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;
它只是有效。
这“仅通过引用明确地传递”是绑定操作的安全特征;因为绑定执行可以持续超出当前状态,所以它要求调用者只能通过引用明确绑定,从而减少意外悬空引用的可能性。