sharptooth
sharptooth

Reputation: 170489

What does C++03 12.4/12 say about calling a base class destructor explicitly through the pointer?

According to C++03 12.4/12 when a destructor is invoked explicitly

if the object is not of the destructor’s class type and not of a class derived from the destructor’s class type, the program has undefined behavior

So I have this code:

class Base {};
class Derived : public Base {};

char memory[100];
new(memory) Derived();
Base* ptr = (Base*)memory;
ptr->~Base();

Here the object is of type Derived and "the destructor's class type" is Base and so it looks like according to the Standard wording there're no grounds for UB.

So does the code above yield UB according to the Standard?

Upvotes: 5

Views: 148

Answers (3)

user541686
user541686

Reputation: 210515

It's not UB, since both classes have trivial destructors, and therefore calling the destructor has the same effect as not calling the destructor (and not calling the destructor is certainly not UB).

Upvotes: 1

user1810087
user1810087

Reputation: 5334

please correct me if i'm wrong, i think there isn't undefined behavior but still should be avoided in sence of humanity (or maintainablity). but, consider Derived is creating some kind of member, e.g. a shared pointer, (which is not untypical even for exceptions :). i tried this code on my machine and also on codepad:

class Base {
public:
  boost::shared_ptr<int> x;
};
class Derived : public Base {
public:
  boost::shared_ptr<int> y;
};


int main(int argc, char *argv[]) {
  boost::shared_ptr<int> xx(new int(0xff));
  boost::shared_ptr<int> yy(new int(0xaa));

  int memory[100];
  for(int i=0; i<100; i++)
    memory[i] = 0;
  Derived* foo = new(memory) Derived();
  foo->x = xx;
  foo->y = yy;
  (*foo->y)--;
  Base* ptr = (Base*)foo;

  ptr->~Base();

  Derived* bar = new(memory) Derived();

  bar->x = xx;
  bar->y = yy;

  foo->~Derived();

  return 0;
}

here is that the shared_ptr yy isn't released, and nobody could guarantee to never forget about Derived shouldn't provide any kind of stuff.

Upvotes: 0

Steve Jessop
Steve Jessop

Reputation: 279265

Correct, there's no undefined behavior.

By contrast there is potential UB in this case depending on the types involved:

Base *ptr = new Derived();
delete ptr;

The reason is that for some types an adjustment might have been applied by the implementation to get from Derived* to Base*. So without the pointer to the complete object there's no way to free the memory allocation correctly. A virtual destructor ensures that the Base sub-object provides enough information for the implementation to recover that (the virtual call mechanism must be able to recover the Derived* pointer in order to pass it as this).

But in your example the memory isn't freed and so there's no motivation to make it UB. Of course it's still a bad idea, since conceptually the Derived object is in a broken state. You have no legitimate way to call ~Derived, even. In your example though both types are trivially destructible, so there's no need to call the destructor of either.

Upvotes: 4

Related Questions