我有这样的代码:
class MyClass
{
typedef void (B::*F)(A*,C);
private:
A* member_pointerA;
F memberPointerB;
void my_class_method()
{
if (some_condition)
// call a callback Function
callback1();
if (member_pointerA && memberPointerB)
//call another function and pass this
callback2(this);
}
};
my_class_method
是一种类方法。 member_pointerA
和memberPointerB
是指向A
的指针和指向void (B::*Something)(A*,C)
类型的函数指针。在代码中以某种方式出现这种情况:callback1()
似乎是一个函数,它导致调用MyClass
的{{1}}类型的对象的析构函数的调用。但是由于函数执行没有完成,应该检查第二个my_class_method
条件是否有被破坏的对象。在if
之前调用callback1()
和member_pointerA
为NULL,但在调用之后它们会以某种方式变为NULL,并且程序崩溃。当我交换位置memberPointerB
时,不考虑if
条件,因为两个指针都为空。那么解释在删除对象后,成员指针将其值从NULL更改为某些垃圾?
答案 0 :(得分:1)
如果我理解正确,callback1
可能会删除调用它的对象,可能是通过调用堆栈中的某个地方的delete this;
。如果是这种情况,那么在执行callback1
之后,您可能无法对该对象执行任何操作,这意味着调用任何非静态成员函数并使用任何非静态成员变量会产生未定义的行为:
void my_class_method()
{
if (some_condition)
// call a callback Function
callback1(); //maybe calls "delete this"
if (member_pointerA && memberPointerB) // use of member variables -> UB!!!
//call another function and pass this
callback2(this); // use of "this" -> UB!!!
}
注意:如果callback2
不是MyClass
的方法,则调用本身不是UB,但函数肯定会尝试访问传递的对象,那将是UB,因为它是访问已删除的对象。
最好的做法显然是没有一个回调来删除它所调用的对象。在极少数情况下,自我删除是正确的做法,但它应该以非常明显的方式发生,而不是通过一些回调在幕后发生。
如果你必须在my_method
的过程中删除对象,最明显的方法是在方法中调用delete this
而不在某些回调中调用它。 callback1
然后可以返回一些值,表明该对象应该删除与否:
void my_class_method()
{
if (some_condition)
{
bool doSelfDelete = callback1();
if (doSelfDelete)
{
delete this;
return;
}
}
}
另一种可能性是使用智能指针(无论如何都是一个不错的选择)并通过指导shared_ptr
到this
来延长对象的生命周期:
void my_class_method()
{
auto self = shared_from_this(); //this is a standard library function, you need to derive from std::enable_shared_from_this<MyClass> to use it.
if (some_condition)
{
callback1(); //won't call a explicit delete since we are working with smart pointers, but may erase some shared_ptr to this object
// but since "self" is a shared_ptr too, it won't destroy this object
}
if (member_pointerA && memberPointerB) //ok
{
callback2(self); //since we don't use raw pointers any more...
}
} //now when self gets destroyed, "this" might get deleted as well.
如果由于某种原因 成为自我删除的回调,你可以做些什么:
让callback1
返回指示对象是否已被删除的内容(您无法设置成员变量,因为如果已删除它,则无法访问该成员变量):
void my_class_method()
{
if (some_condition)
{
bool isDeleted = callback1(); //maybe calls "delete this"
if (isDeleted) return; //since isDeleted is not a member, you may use it
}
}
如果两个条件相互排斥,请使用else if
:
void my_class_method()
{
if (some_condition)
{
callback1(); //maybe calls "delete this"
}
else if (member_pointerA && memberPointerB)
{
callback2(this);
}
}
虽然从概念上讲这可能相同或不同,但这是一个巨大的差异,因为如果第一个条件为假,则第二个条件得到评估,因此callback1
并且自我删除不会发生。
如果两个回调的顺序无关紧要,请更改它,以便callback1
是可以执行的最后一个:
void my_class_method()
{
if (member_pointerA && memberPointerB)
{
callback2(this);
}
if (some_condition)
{
callback1(); //maybe calls "delete this"
}
}
答案 1 :(得分:0)
未定义对象删除后指针的值。我经常使用一个调用delete
运算符的宏,然后将零指定给指针。