alexgolec
alexgolec

Reputation: 28282

A destructor - should I use delete or delete[]?

I am writing a template class that takes as an input a pointer and stores it. The pointer is meant to point to an object allocated by another class, and handed to the this containing class.

Now I want to create a destructor for this container. How should I free the memory pointed to by this pointer? I have no way of knowing a priori whether it is an array or a single element.

I'm sort of new to C++, so bear with me. I've always used C, and Java is my OO language of choice, but between wanting to learn C++ and the speed requirements of my project, I've gone with C++.

Would it be a better idea to change the container from a template to a container for an abstract class that can implement its own destructor?

Upvotes: 7

Views: 561

Answers (11)

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84239

Since pointer in C++ does not tell us how it was allocated, yes, there's no way to decide what deallocation method to use. The solution is to give the choice to the user that hopefully knows how the memory was allocated. Take a look at Boost smart ptr library, especially at shared_ptr constructor with second parameter, for a great example.

Upvotes: 1

Michael Burr
Michael Burr

Reputation: 340486

If you have a class that takes a pointer it's going assume ownership of, then the contract for the use of the class needs to include one of a couple things. Either:

  • the interface needs to indicate how the object the pointer is pointing to was allocated so the new owner can know how to safely deallocate the object. This option has the advantage of keeping things simple (on one level anyway), but it's not flexible - the class can't handle taking ownership of static objects as well as dynamically allocated objects.

or

  • the interface needs to include a mechanism where a deallocation policy can be specified by whatever is giving the pointer to the class. This can be as simple as providing a mechanism to pass in a functor (or even a plain old function pointer) that will be called to deallocate the object (preferably in the same function/constructor that passes in the pointer itself). This makes the class arguably more complicated to use (but having a default policy of calling delete on the pointer, for example, might make it as easy to use as option 1 for the majority of uses). Now if someone wants to give the class a pointer to a statically allocated object, they can pass in a no-op functor so nothing happens when the class wants to deallocates it, or a functor to a delete[] operation if the object was allocated by new[], etc.

Upvotes: 2

anon
anon

Reputation:

Put simply, given only a pointer to dynamically allocated memory there is no way of determining how to de-allocate it safely. The pointer could have been allocated in any of the the following ways:

  • using new
  • using new []
  • using malloc
  • using a user defined function
  • etc.

In all cases before you can deallocate the memory you have to know how it was allocated.

Upvotes: 0

Steven Sudit
Steven Sudit

Reputation: 19630

(Moving my comment into an answer, by request.)

JonH's answer is right (about using array destruction only when you used array construction), so perhaps you should offer templates: one for arrays, one not.

The other answer is to avoid arrays and instead expect a single instance that may or may not be a proper collection that cleans up after itself, such as vector<>.

edit

Stealing blatantly from Roger Pate, I'll add that you could require the use of a smart pointer, which amounts to a single-item collection.

Upvotes: 2

JonH
JonH

Reputation: 33183

Short answer:

If you use [] with new you want to use [] with delete.

//allocate some memory
myObject* m = new myObject[100];

//later on...destructor...
delete m; //wrong
delete[] m; //correct

That was the bare bones, the other thing you could look at is boost. Also quite difficult to answer considering you are not sure if its an array or single object. You could check this though via a flag telling your app whether to use delete or delete[].

Upvotes: 5

R Samuel Klatchko
R Samuel Klatchko

Reputation: 76611

If you don't know whether it was allocated with new or new[], then it is not safe to delete it.

Your code may appear to work. For example, on one platform I work on, the difference only matters when you have an array of objects that have destructors. So, you do this:

// by luck, this works on my preferred platform
// don't do this - just an example of why your code seems to work
int *ints = new int[20];
delete ints;

but then you do this:

// crashes on my platform
std::string *strings = new std::string[10];
delete strings;

Upvotes: 6

Vincent Robert
Vincent Robert

Reputation: 36150

  • Use delete if you allocated with new.
  • Use delete[] if you allocated with new[].

After these statements, if you still have a problem (maybe you want to delete an object that was created by someone else), then you are breaking the third rule:

  • Always delete what you created. Corollary, never delete what you did not create.

Upvotes: 2

user229044
user229044

Reputation: 239521

You shouldn't delete it at all. If your class takes an already initialized pointer, it is not safe to delete it. It might not even point to an object on the heap; calling either delete or delete[] could be disastrous.

The allocation and deallocation of memory should happen in the same scope. Which ever code owns and initializes the instance of your class is also presumably responsible for initializing and passing in the pointer, and that is where your delete should be.

Upvotes: 2

Roger Pate
Roger Pate

Reputation:

You must document how this class expects to be used, and always allocate as expected. You can also pass a flag to the object specifying how it should destroy. Also look at boost's smart pointers, which can handle this distinction for you.

Upvotes: 6

alemjerus
alemjerus

Reputation: 8268

As a general development rule, you should stick to a design where the class which calls new should also call delete

Upvotes: 2

Alexander Torstling
Alexander Torstling

Reputation: 18908

A smart pointer like boost shared_pointer already has this covered, could you use it? linky

Upvotes: 0

Related Questions