So getting back into C++ programming, I’ve been allocating plenty of dynamic memory (using new and new ) . However, I’ve only been using delete , never delete . If fact, I’ll be honest, I forgot about delete , but that’s OK, I didn’t need the  form anyway. Why you ask?
Take this example:
char * buf = new char;
Now, almost every example you see online will actually have delete buf; , this is correct, but unnecessary. Why? The only difference between delete and delete is item deconstruction.
When you call delete, all the memory you allocated with new is still erased. The problem is, only the first element (the one being directly pointed to) is deconstructed. None of the other members of your array are deconstructed. In my example this is OK, because the array was an array of “char”s, you can’t deconstruct a char in C++, it’s not an object.
When is delete useful?
When you allocate an array of objects that themselves allocate more memory. delete makes sure that each entry in the allocated array is properly deconstructed. Example:
class1 * theclass;
theclass = new class1();
class1 * ptr_class1a = new class1;
class2 * ptr_class2a = new class2;
class1 * ptr_class1b = new class1();
class2 * ptr_class2b = new class2();
delete ptr_class1a; // This is OK! All allocated memory will be freed.
delete ptr_class1a; // This is Best.
// It is safest to deconstruct all items, because we don't really
// know what is going on beneath the hood of every class we instatiate,
// and calling delete is just safer all around.
delete ptr_class2a; // This is NOT ok.
// This will only delete the memory reserved for the 5 instances of class2.
// It will NOT free the instances of class1 that each class2 instantiated!.
delete ptr_class2a; // Good. This deconstructs each class2 instance, freeing
// each one's class1 instance. Then all the memory reserved for ptr_class2
// is free. No memory leaks!
delete ptr_class2b; // Good
// delete always deconstructs the first item pointed to (assuming the pointer
//type matches the class type (pointer casting is dangerous!!)). All memory is
delete ptr_class2b; // Acceptable, but not necessary.
// You can delete any pointer, as long as you have not recast the pointer
Can I just call delete all the time?
Sure, well, almost. delete works on a specific type of pointer. When you call myclass * myptr = new myclass , you are telling the system to reserve you sizeof(myclass)*5 bytes of memory. This size is all that is stored in the memory allocator. When you call delete myptr; , the memory allocator goes through the following process:
- How much memory was reserved starting at the address stored in myptr (answer: sizeof(myclass) * 5);
- Start at offset = 0.
- Call the myclass.deconstructor at the address myptr + offset.
- Increase offset by sizeof(myclass)
- If offset < total allocated memory, goto 3. Else, continue;
- Delete/Free all memory reserved (sizeof(myclasS) * 5 bytes) starting at address storef in myptr;.
However, if you tried to call delete (void *) myptr; all calls to sizeof(myclass) above will be replaced with sizeof(void), which returns no size (no object can be of type void). Therefore, none of the objects in the array will be deconstructed. Calling delete (void *)ptr; is the same as calling delete (void *)ptr; .
Similarly, if you recast the pointer to a different type, delete will not know the proper size of each object, and any attempts to deconstruct those “objects” will most likely result in errors/exceptions. Example:
// Using class1 and class2 from above.
class2 *ptr2= new class2;
class1 *ptr1 = (class1 *)ptr2;
delete ptr1; // ERROR
// ptr1 points to memory of sizeof(class2) * 5, but will be interpreted
// as (sizeof(class2) * 5) / sizeof(class1) objects!
// Also, delete will call class1.deconstructor() instead of class2.deconstructor,
// and the BEST CASE scenario is leaked memory (worst case in an error/exception).
Of course, casting pointers in C++ is always dangerous. The compiler and system do not keep track of allocated memory by type, only size. Therefore, you should always be careful when having to cast a pointer.
Note: There are acceptable times to cast a pointer (when reading in bytes that are actually multi-byte values, say casting an int* as a char*), but often times, this can also be handled with Unions.
Anyway, that’s my “quick” overview of the delete and delete operations in C++.