2013-01-15 31 views
2

这是一个基于真正问题的构建方案。如果我有一个基类:删除派生对象时的行为

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; 
}; 

然后说我有一个要求车辆:: run()的定期线程。我有另一个线程,最终删除指向汽车的指针。销毁顺序将导致车辆首先被删除,然后车辆被删除。

如果线程(生活在Vehicle对象中)调用析构函数在汽车中运行后(但显然在车辆被破坏之前)调用incrementStuff函数会发生什么? Car :: incrementStuff是否会被执行并尝试解引用已经被删除的指针?或者将调用Vehicle :: incrementStuff,这是安全的,什么都不做?

假设当Car ::〜Car()正在运行时,线程无法调用Car :: incrementStuff(这是由互斥锁阻止的)。

此代码已被重构,以避免这种情况,但我只是想知道是否有人可以阐明这是如何工作的,或者如果它只是普通的未定义行为?

更一般地说,如果我在Car被破坏之后但在Vehicle之前尝试致电Car :: incrementStuff,会发生什么? NULL检查是否工作,或者内存已经释放,现在可以被任何东西使用?或者,在基础对象被破坏之前,内存是不是“释放”的?

回答

4

你在想这件事。如果您取消引用了已经被delete编辑的指针,则会调用未定义的行为。这就是你真正需要知道的。只要您致电delete ptr;ptr无效。

同步对此对象的访问。

6

如果您删除了Car对象,则后续调用incrementStuff()是未定义的行为。

顺便说一下,您应该在Vehiclevirtual中制作析构函数。请参阅:When to use virtual destructors?

2

一个线程正在读取一个值,而另一个线程正在写入它。这是一场数据竞赛。如果这两个操作未正确同步,则行为未定义。