在这个小例子中,一个对象被多次破坏......
#include <iostream>
#include <string>
#include <memory>
#include <functional>
using namespace std;
struct sA
{
static int n;
int id;
string name;
sA(string s="default"):id(++n),name(s) { cout<<"object '"<<name<<"' created\t id="<<id<<"\taddr="<<this<<"\tn="<<n<<"\n"; }
~sA() { cout<<"object '"<<name<<"' destroyed\t id="<<id<<"\taddr="<<this<<"\tn="<<--n<<"\n"; }
// sA(const sA& other):id(++n),name(other.name+"_Copy") { cout<<"object '"<<name<<"' copied\t id="<<id<<"\taddr="<<this<<"\tn="<<n<<"\n"; }
sA operator=(const sA& other) =delete;
};
int sA::n;
int main()
{
function<void(void)> vp;
{
sA f("1___This Object will die when others need it...");
sA b("2___This Object will not die ...");
vp=[&f,b]
{
cout<<"Hello\n";
cout<<b.name<<"||\t addr="<<&b<<"\t|<*>| Stack Data is ok\n";
cout<<f.name<<"||\t addr="<<&f<<"\t|<*>| Stack Data may not be there\n";
};
vp();
cout<<"********* Block end\n";
}
sA k("3__test obj");
vp();
return 0;
}
到目前为止,我想出的可能原因是:
1)lambda采用的局部对象的引用超出了范围。[对象&#39; f&#39;]
2)调用默认复制构造函数,旧版本被销毁[对象b]
但这些原因并没有回答以下事实:
1)即使在最内部的块结束之前,两个对象也被破坏了。 [确定了块结束]
2)最多必须有1个额外的破坏,但它会显示3. [在程序结束时n = -3]
3)如果我以递归方式启用复制构造函数,则最终会创建副本,但结构总数为no = of destroy&#39;。 [在节目结束时n = 0]
这是lambda的行为(没有变数)吗?
或者它只是代码中的另一个错误?
lambda及其捕获变量的生命周期是什么?
答案 0 :(得分:1)
假设你在代码中修复了未定义的行为,有些副本并不是很明显。
vp=[&f,b]
{
//...
};
该声明中实际上有三份b
。
std::function
构造函数std::function
前两个副本将在语句结束时销毁,因此您会看到两个破坏。它不是被摧毁两次的同一个物体。
std::function
必须进行类型擦除,因此它实际上可能非常昂贵。您可以使用合理的移动构造函数来缓解这种情况,但通常最好在可能的情况下使用原始的lambda类型。
答案 1 :(得分:0)
您的lambda对象通过引用捕获本地对象f
,该对象在“块结束”打印之后超出范围(因此被销毁)。因此,在第二次调用vp()
时,您有一个悬空引用,这是未定义的行为。