Reputation: 10314
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
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
Reputation: 75130
First of all, remember these things:
malloc
need to be deallocated by free
malloc
new
must be deallocated by delete
new[]
must be deallocated by delete[]
delete
for every new
and one delete[]
for every new[]
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...
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
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
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 malloc
s 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
Reputation: 206498
The rules are simple:
new
should be freed with delete
.new []
should be freed with delete []
.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:
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
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