Aslan986
Aslan986

Reputation: 10314

Doubts with destructor

Suppose I have a class:

class ClassX{
   private:
      int* p;
      int i;
   ....
}

And somewhere I do:

ClassX x;
.....
//and in a friend function or in a ClassX function
p = (int*) malloc (.....);

Then when x exit its scope a the destructor is invoked; but it does not free the memory allocated by the malloc right?

And if I redefine it:

ClassX::~ClassX(){ delete [] p; }

it frees the memory allocated by the malloc but not the memory allocated for the class' fields (i.e. i and p)?

Am I missing something?

Thank you.

Upvotes: 1

Views: 114

Answers (6)

Stephane Rolland
Stephane Rolland

Reputation: 39896

To simplify, I always tell myself that a pointer IS only a integer. ( it can be 16, 32 or 64 bits long depending on the system). It's a special integer that helps defining an address, but it is only an integer.

So when you construct class X, it allocates the space for two 'integers'. One called p, the other called i. And when the class is destroyed it desallocate the space of two integers and some stuff.

The destructor doesn't bother what you have done with the value of the special integer p ( that represents an address). You could have created memory as you did, or created a random number: it is all the same in the memory representing class X: only an integer.

Upvotes: 1

Seth Carnegie
Seth Carnegie

Reputation: 75130

First of all, remember these things:

  1. Things allocated by malloc need to be deallocated by free
  2. Don't use malloc
  3. Things allocated by new must be deallocated by delete
  4. Things allocated by new[] must be deallocated by delete[]
  5. One delete for every new and one delete[] for every new[]
  6. Don't use any of the above

Then, you are correct in thinking that, without a destructor, the memory allocated by malloc will not be freed. If you follow the rules above, then you need to use free (not delete[]) to deallocate it:

ClassX::~ClassX() { free(p); }

However, you shouldn't be using malloc in C++ first of all since it doesn't call the constructors of objects, you should use new:

ClassX::ClassX() : p(new int) { }

// NOW we use delete since we used new (not delete[] since we didn't use new[])
ClassX::~ClassX() { delete p; }

However, if you do that, you have to write a copy constructor, copy assignment operator, move constructor, and move assignment operator. So let's look at an even better way:

class ClassX{
private:
    ClassX();

    std::unique_ptr<int> p;
    int i;
    ....
};

// we have to break rule #6 here
ClassX::ClassX() : p(new int) { }

Now you don't even have to write a destructor, you can just let the smart pointer deal with it for you because it will automatically call delete on the thing you made with new when it's destructor is called. Which leads us to...

Your other question:

it frees the memory allocated by the malloc but not the memory allocated for the class' fields (i.e. i and p)?

That's about 1/4 correct. Since i and p are members of the class, they are automatically deallocated when the enclosing class is deallocated, and if they were classes themselves, their destructors would be called. So if you put delete in your destructor, that takes care of the memory allocated by new, and i and p are cleaned up automatically, and everything's good. (You were only 1/4 correct because you used the wrong deallocation function.)

This means that, if you use a smart pointer, the smart pointer's destructor will be called when your object is destructed, and it will automatically deallocates what you allocated with new for you. So you don't even need to worry about it.

This is all assuming you really want to have a dynamic int as part of your class. If you can though, you'd much rather store the int by value (not store a pointer to it) and that way you don't have to mess with smart pointers, deallocation, or any of that other stuff.

Upvotes: 3

Praetorian
Praetorian

Reputation: 109079

If you allocate memory manually you must free it, it is not automatically freed for you.

If you call malloc (or calloc, or realloc) you need to free that memory. Similarly, if you new something delete it, and new[] must be matched by delete[].

That being said, you're programming in C++ and there's rarely a good reason to manage memory manually. Make use of smart pointers, std::shared_ptr for shared ownership and std::unique_ptr otherwise.

Then your class looks like this:

#include <memory>

class ClassX{
   private:
      std::unique_ptr<int> p;
      int i;
      ....
};

ClassX::ClassX() : p( new int ) {} /* No need to deallocate p manually */

Note that unique_ptr has a partial specialization for arrays too, so if p points to an array you can allocate memory as follows:

class ClassX{
   private:
      std::unique_ptr<int[]> p;
      int i;
      ....
};

Class::ClassX() : p ( new int[10] ) {}

You could also completely forget about dealing with pointers and use std::vector or std::array, especially for something simple like an array of ints.

Upvotes: 1

Robᵩ
Robᵩ

Reputation: 168586

The simple rule is: for every malloc there must be exactly one free; for every new, there must be exactly one delete; for every new[] there must be exactly one delete[].

To answer your questions:

[the destructor] does not free the memory allocated by the malloc right?

Correct. It does not. In that case, you have invoked malloc, but never free.

[the modified destructor] frees the memory allocated by the malloc but not the memory allocated for the class' fields?

Wrong. It doesn't free the memory (you must use free, not delete[] in this case. free is mallocs partner. delete[] is new[]'s partner. You can't switch partners.)

Also wrong, it does free the memory allocated for the class's fields (assuming that the fields are non-pointer types.) Freeing the memory occupied by an object occurs after the destructor returns.

Am I missing something?

If you are going to use raw pointers, you also need to understand the Rule of Three. But, better yet, never use raw pointers. Use a smart pointer or a container.

Upvotes: 3

Alok Save
Alok Save

Reputation: 206498

The rules are simple:

  • A memory allocated with new should be freed with delete.
  • A memory allocated with new [] should be freed with delete [].
  • A memory allocated with malloc() should be freed with free().

Note that you need to pass the exact same address returned by the allocating functions to the deallocating functions.

Good Practices:

  • It is always a good practice to avoid dynamic allocations unless you really need them.
  • If you must, You should use some sort of an smart pointer which suits your requirements, the decision of which smart pointer to use depends on ownership and lifetime semantics involved.
  • In C++ there it is rare that one would need to use malloc and free and don't use them unless you have good reasons to do so,

Also,In your case you also need to follow the Rule of Three in order that your program works correctly.

Upvotes: 1

Benj
Benj

Reputation: 32398

You are correct that your destructor should free p, but if you allocate with malloc you should free the memory with free. Alternately you could allocate the memory with:

x.p = new int[size];

This would mean that your delete[] p; destructor would be correct.

With regard to the member variables of the class you don't need to worry about deleting those, if your object was allocated on the stack, they'll be deleted when the stack unwinds. If your class was allocated on the heap, they'll be deleted when you delete x;. Either way, their lifetime is linked to the object that contains them.

Upvotes: 1

Related Questions