0

I'm new to C++ and I have a question.

Lets assume you declared the variable x using the following code:

MyClass *x = new MyClass();

After using this variable, I no longer need it.

Among the following propositions, what would then be the preferred course of action and what's the difference?

  1. Call free(x);

  2. Call x->~MyClass();

  3. Call MyClass::~MyClass(p);

  4. Call delete x;

Can someone help me to understand this?

Thanks In advance.

Daniel Langr
  • 18,256
  • 1
  • 39
  • 74
jbond
  • 47
  • 2

2 Answers2

4

Variable dynamically allocated with the new keyword should be deleted by using the delete keyword. new and delete call the constructor and the destructor of the specified class. This means your instance is initalized and deinitialized properly.

So, instance x initialized with MyClass *x = new MyClass(); should be deleted with delete x;.

However, it is always better, if possible, to declare variable on stack like MyClass x; and let RAII do its work. Take a look at the following example:

{
    // creates an object 'x' on stack
    MyClass x;

    // do something with 'x'

    // once the object is out of scope, it is automatically being destructed
}

Furthermore, if you still need dynamic allocation, modern C++ suggests using smart pointers, like std::shared_ptr and std::unique_ptr. Smart pointers automatically take care of memory handling instead of you. In other words, by using smart pointers, you don't need to care about deleteing the object created with the new. You can write something like:

{
    // creates an object 'x' on heap
    // its default ctor is being called
    std::shared_ptr<MyClass> x = std::make_shared<MyClass>();

    // once the object is out of scope, even though it is allocated
    // on the heap, there is no need to call 'delete' here because
    // deletion is automatically handled by the 'std::shared_ptr'
}
NutCracker
  • 9,614
  • 2
  • 36
  • 62
  • note that the important point of RAII is that `x` is destroyed no matter what, also when there is an excpetion (or `return`), if the scope would be left always at `}` then actually using `new` and `delete` wouldn't be that critical. Just realized that your "//once the object is out of scope" suggests that you always leave the scope at `}`, because I ended up with a similar example to yours. Anyhow you have my +1, – 463035818_is_not_a_number Mar 06 '20 at 12:50
  • @idclev463035818 yes, thanks for pointing that out. Anyway, you have my +1 too. – NutCracker Mar 06 '20 at 12:58
4

If you create an instance via new :

MyClass *x = new MyClass();

you must delete it via delete:

delete x;

1.) Call free(x);

No. free only releases memory it does not call destructors. If you malloc memory you need to free it, but it is rare that you have to use malloc in C++ and calling free on a pointer obtained from new is wrong.

2.) Call x->~MyClass();

No. Explicitly calling the destructor is almost always wrong!

(For example when you create an object via placement new then you don't call delete but the destructor directly, because placement new creates the object in already allocated memory.)

3.) Call MyClass::~MyClass(p);

No. This makes no sense, destructors take no parameters.

4.) Call delete x;

Yes. Calling delete...

Destroys object(s) previously allocated by the new expression and releases obtained memory area

But you should not manually manage memory. Either rely on automatic storage:

MyClass x;

The detructor of x is called automatically when it goes out of scope. Or if you really need dynamic memory allocation use smart pointers.

For further reading: Why should C++ programmers minimize use of 'new'? By the way, this is such a common misconception that each talk of Stroustrup i remember has an example that uses new to create an object and then he explains that it should definitely not use new. Actually there is more to it than forgetting to call delete. Consider:

 { 
     MyClass *x = new MyClass();
     foo();   
     delete x;   // phew I didnt forget to call delete
 }

If foo throws an exception then this code leaks memory. The right way is to rely on RAII:

 { 
     MyClass x;
     foo();   
 }

Now if foo throws an exception, the destructor of x will be called!

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126
  • I agree with the delete part. Next to that, within my company it is practice to always let this pointer point to 0, e.g. ```delete x; x = 0;``` – dejoma Mar 06 '20 at 13:03
  • @dejoma coincidentally I answered a question about that just recently. Setting the pointer to `nullptr` has a (limited) use, but its main effect is a false sense of security. See here: https://stackoverflow.com/a/60522321/4117728 . It does not solve the general problem that comes with using `new` and `delete` manually – 463035818_is_not_a_number Mar 06 '20 at 13:10
  • *Next to that, within my company it is practice to always let this pointer point to 0* -- There is only one reason I know of why this has any effect -- A 0-pointer indicates that the object needs to be allocated. If it's used like this: `if (ptr != nullptr) delete ptr;` the check for nullptr can be entirely removed, since deleting a nullptr is perfectly valid. If it's used because your program flow takes so many twists and turns that you don't know the state of your pointer, then the code probably needs to be reviewed. – PaulMcKenzie Mar 06 '20 at 13:39
  • "*If you create an instance via `new` ... you must delete it via `delete`*" - except when you use `placement-new`, then don't use `delete` at all, you must call the type's destructor directly ala #2 instead – Remy Lebeau Mar 06 '20 at 17:48
  • @RemyLebeau thanks, added a note. I think the "If ... you must" is still fine because it refers to OPs code – 463035818_is_not_a_number Mar 06 '20 at 18:11