C++11 C++;11:防止lambda范围捕获错误 在C++中,与C语言等语言形成对比,可以指定是否包含范围变量的值是由lambda表达式中的值或引用来捕获的。这导致了一种未定义的情况,在这种情况下,可以通过引用在调用lambda表达式之前返回的函数来传递包含范围的lambda: void test() { int t = 1; enqueue_task([&]() { do_something(t); }); }

C++11 C++;11:防止lambda范围捕获错误 在C++中,与C语言等语言形成对比,可以指定是否包含范围变量的值是由lambda表达式中的值或引用来捕获的。这导致了一种未定义的情况,在这种情况下,可以通过引用在调用lambda表达式之前返回的函数来传递包含范围的lambda: void test() { int t = 1; enqueue_task([&]() { do_something(t); }); },c++11,lambda,C++11,Lambda,在这种情况下,当lambda表达式指定的任务计划执行时,“t”很可能超出范围。显然,这会导致丑陋的bug 我的解决方案是这样一种语言功能: template<class T> void enqueue_task(T lambda) { static_assert(!std::is_lambda<T>::value || std::is_lambda_captured_by_value<T>::value, "The lambda exp

在这种情况下,当lambda表达式指定的任务计划执行时,“t”很可能超出范围。显然,这会导致丑陋的bug

我的解决方案是这样一种语言功能:

template<class T>
void enqueue_task(T lambda)
{
    static_assert(!std::is_lambda<T>::value || std::is_lambda_captured_by_value<T>::value,
        "The lambda expression is executed asynchronously and therefore capturing eclosing state via reference is forbidden.");

    // enqueue task for execution
}
这将确保编译器能够确保传递的lambda函数适合延迟执行,也就是说,当它的封闭范围消失时


我认为C++ 11已经有很长的路要走,使C++程序安全。lambda是少数几个你仍然用枪指着自己脚的地方之一。这只是一颗滴答作响的定时炸弹。

通常的补救办法是按值捕获
[=](){…}

当无法复制实际对象时,通常通过
共享的\u ptr
使用它是有益的,这可能会提供更便宜的复制,具体取决于上下文,还允许您共享所有权,以便调用方和延迟的lambda都能独立使用它

C++14应该具有移动捕获语义,这将解决不需要共享时复制对象的性能问题


否则,通过ref传递就是您想要的。就像C++中的所有东西,不仅仅是在lambda中,当你开始传递指针和引用时,你需要小心。

“目前看来,一个明智的解决方案似乎是在延迟执行情况下不允许任何lambda表达式。”然后你就失去了形成闭包的能力。@ Ofc,但我并不是说不允许标准的明智的。但更明智的是API。因此,如果lambdas对您的API的可用性没有贡献,并且用户可能会忘记您的API调用lambdas deferred,那么您不应该将lambdas用于此API。API应该强制正确使用。没错,但lambda表达式并不是唯一可以解决您担心的问题的方法。如果用户传递了一个非lambda函数,该函数执行了一些涉及范围外引用的混乱操作,会发生什么情况?或者,上帝禁止,原始指针?真正强制正确使用API的唯一方法是防止用户向其提供任何类型的输入(即使不这样做,如果您不小心设置约束,也可能会导致误报,因为有效参数的设置方式与您的要求不符,因此会被拒绝).请注意,C++14显然支持在lambdas中通过移动进行捕获,但这很可能是解决您的问题的(未来)解决方案。我还没有完全明白如何用这个来解决我的问题:P?非lambda不是很危险,因为人们会更加小心(我希望)。但是我看到我自己好几次通过引用写lambdas,后来被称为-。-。在这里犯错误太容易了。好吧,我把这个标记为anwser,尽管JAB之前确实说过这件事,但只是作为一个评论:P。@saint Note,他说了一些。这里重要的部分是价值捕获;如果您需要相同的对象,请使用“按值共享”命令。由于原子操作的原因,在某些情况下,复制共享_ptr仍然有点昂贵,这就是我提到移动捕获语义即将出现的原因。
void test()
{
    int t = 1;
    enqueue_task(deferred () { do_something(t); });
}