回顾一个相当古老的项目,我发现了以下奇怪的代码片段(仅提取相关代码):
class CCuriousClass {
~CCuriousClass();
CSomeType* object;
};
CCuriousClass::~CCuriousClass()
{
while( object != NULL ) {
delete object;
}
}
我是否监督过任何事情,或者这是一条未定义行为的明确之路?
我在这里看到的是,如果object
是CCuriousClass::~CCuriousClass()
被调用点的空指针,一切都会好的 - 不采取任何行动 - 但如果object
不为空将是一个内部未定义行为的无限循环。
这很可能是一个我不明白的错误或智能构造吗?
答案 0 :(得分:13)
这看起来像个错误。
答案 1 :(得分:9)
可能是某些疯子已经实现了CSomeType
并对其拥有的CCuriousClass
进行了反向引用,并且其析构函数有时会创建替换。像这样:
class CSomeType
{
public:
explicit CSomeType(CCuriousClass &parent) : parent(parent) {}
~CSomeType()
{
parent.object = respawn() ? new CSomeType(parent) : 0;
}
private:
CCuriousClass &parent;
};
我并不是说任何人都应该编写这样的扭曲逻辑。它可能仍然提供未定义的行为,因为我相信允许delete
修改指针。但它可以解释为什么有人可能认为给定的代码可能有效。
另一方面,它可能只是由于误解了delete
的工作原因造成的错误。
答案 2 :(得分:6)
因为你的问题似乎意味着“有人会对此有什么意义?”而不是“为什么这是一个奇妙的想法?”我建议如下:
class CSomeType {
CCuriousClass* m_plistentry;
CSomeType* m_pnext;
~CSomeType() {
m_plistentry->object = m_pnext;
}
};
基本思想可能是所有者指向列表的头部,而列表只能在头部删除。如果头被删除,它会将其父指针设置为列表的新头。如果父进程被破坏,则会破坏每个列表元素。
现在这显然是来自疯狂城镇的代码。
答案 3 :(得分:3)
正如你所说,这是一个错误。 delete没有将它删除的指针设置为NULL,所以你所拥有的是一个无限循环,它可能会或可能不会被你从删除同一指针两次得到的未定义行为所终止。
答案 4 :(得分:2)
如果CSomeType的实例知道存储指向自身的指针的地址(CSomeType中的CSomeType **成员),那么这种行为是可能的,这样它就可以在删除时重置它。我不知道为什么需要它。
示例:
struct self_know{
self_know** pptr;
int cnt;
static self_know* create(self_know **_pptr){
*_pptr = ::new self_know;
(*_pptr)->cnt = 10;
(*_pptr)->pptr = _pptr;
return *_pptr;
}
void operator delete(void*it){
self_know *s = (self_know*)it;
if(--s->cnt<0){
*(s->pptr)=0;
::delete s;
}
}
};
#include<iostream>
main(){
self_know *p = 0;
self_know::create(&p);
while( p != 0){
std::cout << p->cnt << std::endl;
delete p;
}
}
答案 5 :(得分:2)
另一个可能的理论是,有人用预处理器玩了一个讨厌的技巧。说:
struct delete_and_null {
template<class T>
delete_and_null& operator, (T*& p) {
delete p;
p = 0;
return *this;
}
} delete_and_null;
#define delete delete_and_null,
这并不能解释循环的必要性,但至少它会避免U.B.并最终终止。
答案 6 :(得分:1)
这似乎是一个错误,除非CSomeType
的析构函数可以某种方式修改此对象。
答案 7 :(得分:1)
它不仅可能是一个bug,而且它是一个绝对毫无意义的检查,因为删除空指针很好。替换为
CCuriousClass::~CCuriousClass()
{
delete object;
}
或更好地使用智能指针并完全摆脱析构函数。
答案 8 :(得分:1)
查看CSomeType类定义。可能存在“!=”函数重载。否则它显然是一个错误。
答案 9 :(得分:0)
守则似乎有些错误。 确保析构函数不应抛出任何异常否则它可能会终止程序,它应该是。
CCuriousClass::~CCuriousClass()
{
try
{
if( object != NULL )
{
delete object;
object = NULL;
}
}
catch(...)
{ }
}
答案 10 :(得分:0)
我怀疑这是来自一个疯狂的C程序员,他不了解析构函数和/或操作符删除。无论是那个还是那些笨拙地输入'while'而不是'if'并且不知道删除已经检查为null的人。
我不会浪费时间推测疯子代码。重要的是要认识到它是愚蠢和疯狂的。