C++ 这种奇怪的组合会是什么;而";及;删除“;什么意思?
回顾一个相当老的项目,我发现了以下奇怪的代码片段(仅提取了相关代码): 我是否监督过任何事情,或者这是一条通向未定义行为的简单道路 我在这里看到的是,如果C++ 这种奇怪的组合会是什么;而";及;删除“;什么意思?,c++,memory-management,pointers,C++,Memory Management,Pointers,回顾一个相当老的项目,我发现了以下奇怪的代码片段(仅提取了相关代码): 我是否监督过任何事情,或者这是一条通向未定义行为的简单道路 我在这里看到的是,如果object在CCuriousClass::~CCuriousClass()被调用的点上是一个空指针,那么一切都会很好-没有采取任何操作-但是如果object不是空的,那么这将是一个内部行为未定义的无限循环 这很可能是一个bug还是一些我不理解的智能构造?这看起来像个bug。代码似乎有bug。 请确保析构函数不应抛出任何异常,否则它可能会终止程
object
在CCuriousClass::~CCuriousClass()
被调用的点上是一个空指针,那么一切都会很好-没有采取任何操作-但是如果object
不是空的,那么这将是一个内部行为未定义的无限循环
这很可能是一个bug还是一些我不理解的智能构造?这看起来像个bug。代码似乎有bug。 请确保析构函数不应抛出任何异常,否则它可能会终止程序,并且应该是这样
CCuriousClass::~CCuriousClass()
{
try
{
if( object != NULL )
{
delete object;
object = NULL;
}
}
catch(...)
{ }
}
由于你的问题似乎暗示“有人可能对这件事有什么意思?”而不是“为什么这是一个奇妙的想法?”我建议如下:
class CSomeType {
CCuriousClass* m_plistentry;
CSomeType* m_pnext;
~CSomeType() {
m_plistentry->object = m_pnext;
}
};
其基本思想可能是,所有者指向列表的标题,而列表只能在标题处删除。如果头被删除,它将其父指针设置为列表的新头。如果父元素被销毁,它将销毁每个列表元素
这显然是来自疯狂小镇的代码 正如你所说,这是一个bug。delete不会将它删除的指针设置为NULL,因此您拥有的是一个无限循环,它可能会也可能不会因两次删除同一指针而导致的未定义行为而终止。这似乎是一个bug,除非CSomeType的析构函数能够以某种方式修改此对象。这不仅可能是一个bug,而且是一个毫无意义的检查,因为删除空指针是可以的。取代
CCuriousClass::~CCuriousClass()
{
delete object;
}
或者最好使用一个智能指针,完全去掉析构函数。可能是一些疯子实现了
CSomeType
,并反向引用了它所拥有的CCuriousClass
,而它的析构函数有时会创建一个替换。大概是这样的:
class CSomeType
{
public:
explicit CSomeType(CCuriousClass &parent) : parent(parent) {}
~CSomeType()
{
parent.object = respawn() ? new CSomeType(parent) : 0;
}
private:
CCuriousClass &parent;
};
我并不是说任何人都应该写出这样扭曲的逻辑。它可能仍然会给出未定义的行为,因为我相信delete
可以修改指针。但这可能解释了为什么有人认为给定的代码可能是有效的
另一方面,这可能只是一个错误,它是由于误解了
delete
的工作原理而导致的。如果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;
}
}
struct self\u know{
自知**pptr;
int-cnt;
静态自知*创建(自知**\u pptr){
*_pptr=::新的自我认识;
(*_pptr)->cnt=10;
(*\u pptr)->pptr=\u pptr;
返回*_pptr;
}
void操作符删除(void*it){
self_know*s=(self_know*)it;
如果(--s->cntpptr)=0;
::删除s;
}
}
};
#包括
main(){
自知*p=0;
自知::创建(&p);
while(p!=0){
std::cout cnt查看CSomeType类定义。可能存在“!=”函数重载。否则这显然是一个bug。另一个可能的理论是有人对预处理器耍了一个恶作剧。比如:
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,
struct delete_和_null{
模板
删除_和_null&运算符(T*&p){
删除p;
p=0;
归还*这个;
}
}删除_和_null;
#定义delete_和_null,
这并不能解释循环的必要性,但至少它会避免U.B.并最终终止。我怀疑它来自一个疯狂的C程序员,他不理解析构函数和/或运算符delete。或者是他笨拙地输入了“while”而不是“if”,并且不知道delete已经检查了null
我不会浪费时间去猜测疯狂的代码。重要的是要认识到它是愚蠢和疯狂的。也许在另一个线程中该对象发生了什么事?我不知道,但你能重载对象的“删除”操作符吗?@Mike,你能,但对象析构函数仍然会被调用。它看起来是错误的。即使它工作正常(因为一些愚蠢的析构函数代码)应该对它进行高度评论,以准确描述正在发生的事情。然后,当有理智的人看到它并阅读评论时,他们应该重新考虑,使它像普通代码一样工作。它不能更改原始代码中被删除的指针。@Neil我很好奇,你为什么不能这样做?@Neil,是的,我也很好奇。这看起来像是一个有效的exp对我来说,我收回它,它可以,当然前提是原始类设置了指针,但显然它没有。这种构造将是邪恶的。这很美!:p从现在开始,我将编写所有这样的析构函数。respawn()当然,应该返回一个用于真正邪恶的随机比特<代码>删除< /代码>不允许修改它的操作数(因为它甚至不需要是一个左值-考虑<代码>删除新的int /代码>),所以这里没有U.B.,只是纯粹的邪恶。
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,