Avoiding memory leaks when deleting data of a template Object. (C++)

67 Views Asked by At

Assume the following struct:

template <typename T>
struct A{
  T* pointer;
  void clearData(){
    //delete data pointer is pointing to
    data->~T(); //call destructor?
    pointer = nullptr;
  }
};

If I want to provide a function that clears the Data where pointer is pointing to - how would I go about this? I am aware of the new/delete, new[]/delete[] and malloc()/free() combinations but since T is templated I dont't know if the data was allocated using new, new[] or malloc(). From my understanding the destructor should always free up the allocated memory. So if I explicitly call the destructor there should be no memory leaks (if the destructor of the object is implemented correctly). Are my assumptions correct or are there cases where this could lead to problems? If so please provide an example so I get a better understanding of the issue.

Note: Answers like "you should use smart pointers because explicitly calling the destructor is bad practice" are not helpful as I am trying to understand WHY it would cause issues in my case. And I see explicit destructor calls as a valid option if it can't lead to any issues.

1

There are 1 best solutions below

2
Yksisarvinen On

From my understanding the destructor should always free up the allocated memory.

No. Destructor should release owned resources. It is not clear that A owns anything, especially if it didn't allocate the resource on its own, but got it from somewhere else. And resources are not just allocated memory (could be e.g. open file handle), but that's not really related to the topic.

So if I explicitly call the destructor there should be no memory leaks (if the destructor of the object is implemented correctly).

Absolutely not. You are not allowed to call destructor of an object unless it was created with placement new. And if it was, calling destructor will do what ~T() does, but will do nothing to the memory it was occupying, which likely still needs to be released.

explicitly calling the destructor is bad practice

It's not bad practice, it's straight up Undefined Behaviour (except for that one case mentioned earlier).


In your case, A should not take ownership of data and make it clear in documentation that it wants a handle to T which will not be released in any way.

If you really think A should own data, you need to also accept a deleter that will be able to release data properly, because only the caller has knowledge on how to release it correctly (if it needs releasing at all) - just like std::unique_ptr does. And at this point, you could also just accept std::unique_ptr and forget about the issue altogether.