我在其中一个项目中看到了一个奇怪的行为。情况如下:
Victim
,它包含指针变量,构造函数和析构函数。Perpetrator
,其构造函数接受一个Victim
对象,并将指针变量复制到里面的具体变量中。Victim*
,并使用new
创建了对象,然后通过Perpetrator
将其提供给Perpetrator(*victim)
。Perpetrator
的构造函数完成后,将调用Victim
的析构函数并删除对象。问题是Victim
的唯一副本,poor
在构建过程中被完全销毁。通过delete poor
在最后整理程序将导致双重自由错误。
行为在C ++ 98/11,GCC 4.8.5,7.x和LLVM CLANG中是一致的,因此必须明确定义。调用了什么行为,它的语义是什么?
我的理论是,由于constructor
接受一个具体的对象,它被认为是复制的,所以当constructor
/ function
完成时它会被破坏。
由于我赞美PoC||GTFO
,所以这里是代码:
澄清:该示例是故意编写的,因为它是一个更复杂但非泄漏且管理良好的数据结构复杂的简化模型。删除所有必要的位使它看起来像一个可怕的破坏代码。在实际代码Victim
中是一个长生存数据存储,Perpetrator
是用于处理所述数据的临时存储变量。
#include <iostream>
using namespace std;
struct Victim
{
double* pointer;
Victim ()
{
this->pointer = new double(42.2);
}
~Victim ()
{
cout << "Destructor of the Victim is called." << endl;
delete this->pointer;
}
};
struct Perpetrator
{
double concrete;
Perpetrator (Victim victim)
{
concrete = *(victim.pointer);
}
};
int main ()
{
Victim* poor = new Victim();
Perpetrator cruel(*poor);
cout << cruel.concrete << endl;
}
示例输出:
./destructor_test
Destructor of the Victim is called.
42.2
答案 0 :(得分:4)
Perpetrator (Victim victim)
- 正在通过值传递对象。表示必须(复制)构造,然后在调用结束时销毁。
事实上,根本不需要使用new
。这样:
int main ()
{
Victim poor;
Perpetrator cruel(poor);
cout << cruel.concrete << endl;
}
行为相似。你会看到两个结构和两个破坏。原始代码没有展示的第二个,因为你的例子泄露了。
答案 1 :(得分:0)
通过ref传递受害者:
struct Perpetrator
{
double concrete;
Perpetrator (Victim& victim)
{
concrete = *(victim.pointer);
}
};
受害者将建造&amp;每次破坏一次。
答案 2 :(得分:0)
这是你想要实现的吗?
using namespace std;
struct Victim
{
double* pointer;
Victim ()
{
this->pointer = new double(42.2);
}
~Victim ()
{
cout << "Destructor of the Victim is called." << endl;
delete this->pointer;
}
};
struct Perpetrator
{
double concrete;
Perpetrator (Victim *victim)
{
concrete = *(victim->pointer);
}
~Perpetrator ()
{
cout << "Destructor of the Perpetrator is called." << endl;
}
};
int main ()
{
Victim* poor = new Victim();
Perpetrator cruel(poor);
cout << cruel.concrete << endl;
delete poor;
}
<强>输出:强>
42.2
受害者的驱逐者被称为。
调用Perpetrator的析构函数。