7

I have a question about deallocating memory in C++:

typedef struct type1
{
   int a;
   int b;
   float c;
} Type1;

typedef struct type2
{
   int a;
   int b;
} Type2;

void *p = new Type1;

delete (Type2 *)p;

In this case, will be the memory area pointed by p be deleted completely even after p was cast to type of different size?

LihO
  • 41,190
  • 11
  • 99
  • 167
  • 2
    @Johnsyweb `base` doesn't have a virtual destructor, so that's still undefined behavior – Praetorian Jan 02 '13 at 21:42
  • Why don't you introduce a common base class with a `virtual` dtor `struct base { int a; int b; virtual ~base() { } }; struct Type1: public base { float c; }; struct Type2: public base { }; base* p = new Type1; delete p;`? – johnsyweb Jan 02 '13 at 21:45
  • @Johnsyweb: In case you want to use inheritance, it would be easier if Type1 (extended by attribute `c`) is derived from `Type2`. And just like Praetorian has already pointed out, `Type2` (base type) should have virtual destructor. – LihO Jan 02 '13 at 21:45
  • @Liho: That may well be easier, but often the examples given are greatly reduced from the real-world cases. I have now included `virtual ~base() { } `. – johnsyweb Jan 02 '13 at 21:50

3 Answers3

14

The behavior is undefined. In this case, the dynamically allocated object may only be deleted via a pointer of type Type1.

First, by using the pointer obtained by (Type2 *)p in the delete expression, you violate the aliasing rules. There is a limited set of types via which the object pointed-to by p may be used. The rules from C++03 may be found in an answer to another question. The C++11 rules are similar (the differences are not relevant to the answer to your question).

Even if the program did not violate the strict aliasing rules, it would violate the requirements of the delete expression. The specification states (C++11 §5.3.5[expr.delete]/3):

if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.

In your delete expression, the static type of the object is Type2, whereas the dynamic type is Type1. The types are different, but the static type is not a base class of the dynamic type.

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
4

That would be a really bad idea, as you would be asking the compiler to arrange to run Type2::~Type2 on a Type1 pointer, and that destructor might reference off the end of the object.

In conventional environments, the eventual free of the memory would be alright, because operator delete calls free which does not care what type you called it at compile time. However, in a not so conventional environment, it could be a disaster.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
0

Although this question was perfectly answered by James already, I would like to point out one thing:

In proper C++ code, you'll almost never end up working with void pointers, which means your code would probably look like this:

SubType *p = new SubType;
BaseType* pB = (BaseType*)p;
delete pB;

in this case, even if the BaseType would have proper virtual constructor, there is still possible undefined behavior if the SubType is not derived from the BaseType. Common C-style cast isn't very lucky choice here.

But in case you would use dynamic_cast, compiler would most likely not let you do that in case that p doesn't point to object of polymorphic type. And even in case that p points to object of polymorphic type, but BaseType wouldn't be base type of SubType, dynamic_cast would return NULL and you could handle this state appropriately:

SubType *p = new SubType;
BaseType* safePtr = dynamic_cast<BaseType *>(p);
if (!safePtr) // p doesn't point to object of type derived from BaseType
    ...       // handle this situation
else          // p points to object of polymorphic type derived from BaseType
    delete safePtr;
Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167