下面的代码应该打印两个相同的整数,但事实并非如此.JavaScript中的类似程序会打印两个相同的数字.
在C++中似乎是合理的,因为当stdfun
执行时,regfun
已经完成,那时local_var
就不存在了.
所以我的问题是我们如何正确地访问捕获的局部变量超出其上下文的生命周期,就像JavaScript默认情况下那样?
#include#include #include #include #include #include using namespace std; int start_stdfun_in_a_new_thread(std::function stdfun) { int id = rand(); std::function call = [=]() { Sleep(1000);//let regfun finish stdfun(); }; std::async(std::launch::async,call); return id; } void regfun() { int local_var = -1; std::function stdfun = [=,&local_var]() mutable -> void { cout< 很难描述我的问题到底是什么,但我只需要像cavascript一样在c ++中使用的东西.如果你对javascript非常熟悉,也许你可以理解我的意思.
你local_var
受当地环境的束缚,即它在regfun
退出时就已经死了,几乎立刻就会发生.但是你的lambda通过引用捕获它,这意味着在稍后执行时它是一个悬空引用stdfun
,因为那时local_var
已经死了.
所以这是未定义的行为.你需要什么(JavaScript做什么)是延长捕获变量的生命周期.但是,正如http://en.cppreference.com/w/cpp/language/lambda中所解释的那样,C++ 11 lambda不是这种情况:
悬挂参考文献
如果通过引用(隐式或显式)捕获实体,并且在实体的生存期结束后调用闭包对象的函数调用操作符,则会发生未定义的行为.C++闭包不会延长捕获的引用的生命周期.
我看到两个解决方案:
一种解决方案是对要捕获的对象进行堆分配,使用a指向它std::shared_ptr
,并按值捕获此指针(将其复制到lambda实例中).然后,最后一个共享指针实例将为您删除堆分配的对象.
如果可能的话,你也可以在其他一些上下文中定义它,在这种情况下,在每种情况下都超过了它的使用寿命.(在您的简单代码中main
,但在大多数情况下,您希望等待线程;启动和等待线程的上下文很可能是正确的上下文.)然后通过regfun
引用传递给它,并且也通过引用捕获它.因此,即使regfun
退出,它仍然是一个有效的参考(如果它在一个生存的背景下).