Flex Ferrum发布代码示例here(我认为最小,完整且可验证已足够):
#include <iostream>
#include <functional>
using namespace std;
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
m_foo = [this] {std::cout << m_val << std::endl;};
}
~Bang()
{
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void ()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main() {
Bang b(100500);
b.Foo();
b = GetBang();
b.Foo();
return 0;
}
我们不错的Flex还提供live demo
粗略地看,我认为它会输出100500
,但实际输出是:
-1
100500
,而不是-1
) 我在ask box
中写了一些我自己的推理,但发现它更适合作为答案发布(会让问题太长)。如果我的回答有误,请更正,欢迎提供更多答案
答案 0 :(得分:3)
啊,它应该归咎于临时的析构函数 - Bang(100500)
,它返回GetBang
格式,prvalue
,并且temporary object lifetime
。
[this]
will be stored as reference of *this
,就像这样: class Lambda
{
public:
void operator()() const
{
//output
}
private:
Bang& bang;
public:
Lambda(Bang& bang) : bang{bang}
{
}
} lambda{*this};
...
m_foo = lambda;
因为此处否 RVO
,所以,临时Bang(100500)
将首先分配给b
,然后销毁。
促销operator()
,constructor
和destructor
输出一些信息:
#include <iostream>
#include <functional>
using namespace std;
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
std::cout << "Bang(int i = 0) m_val address is " << &m_val << '\n';
class Lambda
{
public:
void operator()() const
{
std::cout << "operator() m_val address is " << &bang.m_val << '\n';
std::cout << bang.m_val << std::endl;
}
private:
Bang &bang;
public:
Lambda(Bang &bang) : bang{bang}
{
}
} lambda{*this};
m_foo = lambda;
}
~Bang()
{
std::cout << "~Bang()\n";
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main()
{
Bang b;
b = GetBang();
b.Foo();
return 0;
}
输出:
Bang(int i = 0) m_val address is 0x7ffd202c48b0
Bang(int i = 0) m_val address is 0x7ffd202c48e0
~Bang()
operator() m_val address is 0x7ffd202c48e0
-1
~Bang()
显示:
dtor
将在输出之前被调用,这意味着临时对象已被销毁。 m_value
的地址不会改变。 这两个保证我们仍然可以从m_value
的{{1}}访问临时b
。
应该未定义行为来访问已销毁的对象,但不需要警告和错误。
要解决这个问题,有两种解决方案:
m_foo()
。这需要c ++ 14。[bang = *this]
。这需要c ++ 17。 live demo
答案 1 :(得分:0)
您可能希望按值*this
将当前对象传递给lambda,以便在复制赋值Bang
时可以存储和复制它。传递指针this
将存储并复制指向复制赋值Bang
时已销毁的临时对象的指针。
这样可以:
#include <iostream>
#include <functional>
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
m_foo = [bang = *this] { std::cout << bang.m_val << std::endl; };
}
~Bang()
{
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main()
{
Bang b;
b = GetBang();
b.Foo();
return 0;
}