这是一个基于真实问题的虚构场景。如果我有基类:
class Vehicle
{
public:
void run() { incrementStuff(); }
virtual void incrementStuff() { }
};
派生类:
class Car : public Vehicle
{
public:
Car() : Vehicle() { stuff = new StuffClass(); }
~Car() { delete stuff; stuff = NULL; }
virtual void incrementStuff() { if (stuff != NULL) stuff->increment(); }
protected:
StuffClass* stuff;
};
然后说我有一个定期调用Vehicle :: run()的线程。我有另一个线程,最终删除指向汽车的指针。破坏的顺序将导致汽车首先被删除,然后是车辆。
如果线程(生活在Vehicle对象中)在析构函数在汽车中运行之后调用incrementStuff函数会发生什么(但显然在车辆被破坏之前)?是否会执行Car :: incrementStuff并尝试取消引用已删除的指针?或者将调用Vehicle :: incrementStuff哪个是安全的,什么都不做?
假设线程在Car ::〜Car()运行时无法调用Car :: incrementStuff(这是由互斥锁阻止的)。
这段代码已被重构以避免这种情况,但我只是想知道是否有人可以阐明它是如何工作的,或者它是否只是简单的未定义行为?
更一般地说,如果我在Car被破坏之后但在车辆出现之前尝试调用Car :: incrementStuff会发生什么? NULL检查是否有效,或者该内存是否已经解除分配并且现在可以被任何内容使用?或者,在基础对象被破坏之前,该内存是否已“释放”?
答案 0 :(得分:6)
如果您删除了Car
对象,则对incrementStuff()
的后续调用是未定义的行为。
另外,您应该在Vehicle
班virtual
中制作析构函数。请参阅:When to use virtual destructors?
答案 1 :(得分:4)
你在想它。如果取消引用已经delete
的指针,则调用未定义的行为。这就是你真正需要知道的。只要您致电delete ptr;
ptr
无效即可。
同步对此对象的访问权限。
答案 2 :(得分:2)
一个线程正在读取一个值,而另一个线程正在写入它。这是一场数据竞赛。如果两个操作未正确同步,则行为未定义。