Search code examples
c++virtualdestructor

Is this a safe code?


My question is do you think that the code shown below is safe? Can this code, as is, generate a run-time failure like: __PureVirtualCalled() at 0x9000000007ef90c?

By the way, I have compiled this code using g++ 4.3.2 on GNU Linux (64 bit). The output is:

~derived called.
~base() called.
~base() called.
foo() called.

Please note that the code given below is just a small program that I wrote to explain the problem. The real class is actually an implementation of a reference counter, that disposes itself only when its count is down to zero. The reason for invoking the destructor manually is to avoid the overhead of a virtual function call (the reference counter class is derived from an abstract counter class). It is possible to suppress virtual call by explicitly specifying the function one is intend to call especially if the class is the most derived one. However, that clearly does not work for virtual destructors.

One more information, the real application which got the above mentioned error is a multi-threaded application.

Please note that I am trying to get an explanation as to why the runtime is raising the above mentioned error. It is doing so intermittently.

The code

#include <iostream>

class base {
public:
    virtual ~base() {
        std::cout << "~base() called." << std::endl;
    }

    virtual void dispose() = 0;

    void foo() {
        dispose();
        std::cout << "foo() called." << std::endl;
    }
};

class derived : public base {
public:
    ~derived() {
        std::cout << "~derived called." << std::endl;
    }

    void dispose() {
        // Intention here is to suppress the virtual function call. 
        this->derived::~derived();
        delete this;
    }
};

int main() {
    base* ptr = new derived;
    ptr->foo();
    return 0;
}

Solution

  • I'm not sure what you're trying to do, but...

    The lines:

    this->derived::~derived();
    delete this;
    

    result in undefined behavior. First you explicitly destruct the object, then you invoke delete, which calls the destructor on what has effectively become raw memory. The delete this; should be enough. The only time you want to explicitly call destructors is when separating allocation and initialization, and in that case, you'll have used placement new to construct the object.