C++ 将输入参数传递给lambda函数中的std::函数

C++ 将输入参数传递给lambda函数中的std::函数,c++,lambda,std-function,C++,Lambda,Std Function,我有一个类,它有一个publicstd::function成员,如下所示: class B { public: B(std::function<void(void)> _func = NULL) : m_function(_func) { } std::function<void()> m_function; }; class A { private: X x; public: B GetObjectB() { s

我有一个类,它有一个public
std::function
成员,如下所示:

class B
{
public:
    B(std::function<void(void)> _func = NULL) : m_function(_func) { }
    std::function<void()> m_function;
};
class A
{
private:
    X x;
public:
    B GetObjectB()
    {
        std::string local = "abc";
        return B(([&]() -> void { x->SomeFunction(local); }))
    }
};
我还有一个类
a
,它返回类型为
B
的对象,如下所示:

class B
{
public:
    B(std::function<void(void)> _func = NULL) : m_function(_func) { }
    std::function<void()> m_function;
};
class A
{
private:
    X x;
public:
    B GetObjectB()
    {
        std::string local = "abc";
        return B(([&]() -> void { x->SomeFunction(local); }))
    }
};
然后我执行

A a;
B b = a.GetObjectB();
b.m_function();
在调用函数
SomeFunction
之前,代码工作正常,并且输入参数
\u s
没有值,尽管已将
local
作为其输入参数传递


我在这里做错了什么?

你告诉你的lambda默认通过引用捕获(
[&]
),它捕获对堆栈上的
本地
的引用。作为一个堆栈变量,它在作用域退出时被解除分配,因此返回对象的
my_函数
捕获了一个悬空引用。尝试
[=]

你告诉你的lambda默认通过引用捕获(
[&]
),它捕获对堆栈上的
本地
的引用。作为一个堆栈变量,它在作用域退出时被解除分配,因此返回对象的
my_函数
捕获了一个悬空引用。试试这段代码

std::string local="abc";
return B(([&]()->void{x->SomeFunction(local);}))
通过引用捕获所有使用的变量,并返回函数。捕获的变量中有局部变量
局部
,其生存期在作用域退出时结束,即从函数返回时结束。因此,当稍后执行lambda时,局部变量不再存在,这意味着捕获的引用无效(“悬挂引用”)

引述自:

悬而未决的参考文献 如果通过引用隐式或显式捕获实体,以及 闭包对象的函数调用操作符在 实体的生存期已结束,出现未定义的行为。C++ 闭包不会延长捕获引用的生存期

这段话表明,在其他语言中,使用闭包支持(例如在JavaScript中),引用引用的变量的生存期被延长,而C++中的变量不是这样的。 变量

x
也存在同样的问题,该变量是调用函数的类
a
的成员变量。虽然您的测试中可能没有问题代码,但这也可能成为一个问题:

B b;

// some other context
{
    A a;
    b = a.GetObjectB();
}

// The lambda previously returned from a.GetObjectB() is now
// stored in b. But it still refers to the now dead a.x!

b.m_function();    // BOOM!
一个简单的解决方法是不通过引用捕获所有变量,而是通过值捕获所有变量,因此变量被复制到lambda实例中:

std::string local="abc";
return B(([=]()->void{x->SomeFunction(local);}))
在我对一个非常类似的问题的回答中讨论了当您不想复制值时可能的解决方法:。

这段代码

std::string local="abc";
return B(([&]()->void{x->SomeFunction(local);}))
通过引用捕获所有使用的变量,并返回函数。捕获的变量中有局部变量
局部
,其生存期在作用域退出时结束,即从函数返回时结束。因此,当稍后执行lambda时,局部变量不再存在,这意味着捕获的引用无效(“悬挂引用”)

引述自:

悬而未决的参考文献 如果通过引用隐式或显式捕获实体,以及 闭包对象的函数调用操作符在 实体的生存期已结束,出现未定义的行为。C++ 闭包不会延长捕获引用的生存期

这段话表明,在其他语言中,使用闭包支持(例如在JavaScript中),引用引用的变量的生存期被延长,而C++中的变量不是这样的。 变量

x
也存在同样的问题,该变量是调用函数的类
a
的成员变量。虽然您的测试中可能没有问题代码,但这也可能成为一个问题:

B b;

// some other context
{
    A a;
    b = a.GetObjectB();
}

// The lambda previously returned from a.GetObjectB() is now
// stored in b. But it still refers to the now dead a.x!

b.m_function();    // BOOM!
一个简单的解决方法是不通过引用捕获所有变量,而是通过值捕获所有变量,因此变量被复制到lambda实例中:

std::string local="abc";
return B(([=]()->void{x->SomeFunction(local);}))

在我对一个非常类似的问题的回答中讨论了当您不想复制值时可能的解决方法:。

这让人倍感不舒服,因为还有一个隐含的假设,即调用函数时,
a
对象是活动的…@KerrekSB感谢您指出这一点,我把它添加到了我的答案中。这让人倍感不舒服,因为还有一个隐含的假设,即调用函数时,
A
对象是活动的…@KerrekSB谢谢你指出这一点,我把它添加到了我的答案中。