Question about free() and memory deallocation

Aug 16, 2008 at 5:53pm
I'm sorry for boring you about SO MANY questions of memory allocation.

Assuming I have

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct C {
 int a, b;
};

struct B {
  C * c;
  int total_C;
};

struct A {
  B * b;
  int total_B;
};

//....

A a;
a.b = (B*) malloc (how_many_B_element * sizeof(B));
a.b[0].c = (C*) malloc (how_many_C_in_that_B_element * sizeof(C));


if I want, at a certain point, to deallocate all memory allocated virtually with malloc

I have to deallocate each b[ID].c memory before b itself

1
2
3
free (a.b[0].c); free(a.b[1].c); 
...
free (a.b);


OR I can free b directly?

1
2
free(a.b); //will it deallocate also all "c" allocations for all "b" element
           //before deallocating "b" itself? 


Ps: I know that helios would be angry becouse I continue to prefer malloc for variable allocation. However I like it more than new in some usage.
(for example I can use realloc to resize allocated memory without losing data of previous allocation).
Aug 16, 2008 at 6:12pm
Well, well. You read my mind. Good. Now I don't have to say it.

No, you have to free(a.b[0..n-1].c) and then free(a.b).
Which is why, in this case, it would be a lot easier to use new. You'd just write the destructor for B and delete[] a.b would do all the work for you.
Aug 16, 2008 at 7:11pm
Eh Eh... Luckly you are kind and you ask my question :P

It is not a great problem for me, I was only thinking about program performance.
Seeing the fact that this ramification si all managed into a class, I need only to make a destructor ;)

However, becouse I am here to learn (even if cpp is only a hobby), I ask to you if exists a way to use new to reallocating memory of a pointer inizialized before.

1
2
3
4
5
6
7
struct A {
 somedata;
};

//....

A * a;


For example assuming that I have allocated space for 3 "A" element at "a" and I need to resize memory, if I use malloc I can use realloc (and I don't lose data saved before).

 
a = (A*) realloc (a, sizeof(A) * new_quantity_of_elements);


But how can I do the same with new?
(perhaps I have to overload operator new, but I don't know how).

It's just for information, becouse I probably continue to use malloc-free in some case and new-delete in other cases.
Aug 16, 2008 at 7:22pm
As far as I know, there's no new equivalent for realloc().
Aug 16, 2008 at 7:23pm
You are using C-Style. In C++, no realloc is needed: containers are used instead, they encapsulate tedious, error-prone, hard to write, read and maintain memory management (and even they don't really encapsulate it, the allocators used by the containers do).
The STL has a concept named Variable Size Container and e.g. std::vector and std::deque are models for it, the former being the official ISO recommendation to substitute the old-style (C-Style) arrays, the latter, being better (faster) in many cases, does not guarantee that the elements are in one memory block, thus is not a good substitute for arrays in all cases (but it therefore does not require relocation at all while approaching vector-like efficiency for random acces).

Edit: there is indeed no C++ version of realloc, as helios stated, for the reasons given above - it is /not needed/.
Last edited on Aug 16, 2008 at 7:24pm
Aug 17, 2008 at 8:19am
If it so, I like more C-style, becouse I want to determine the size of allocation and also to resize allocation by myself if necessary.
As a noob, it seems to me better, even if it is a little harder to manage (but more low-level :) ).

I will use new and delete for other things like to allocate and deallocate memory for "temp" array of chars or similar cases.

Thank for your explainations :)
Last edited on Aug 17, 2008 at 8:22am
Aug 17, 2008 at 8:31am
Do as you please. Me personally, I prefer the paperless office with stone tablets - it's much safer than a RAID...
You should, however, be aware that ~98% of all software security holes are due to buggy memory management. And, if you really do prefer low-level programming, you might want to switch to plain C.
Aug 17, 2008 at 3:44pm
I cannot pass to plain C becouse:
I can use iftsream/ofstream better than fopen
C++ has also the keyworld bool for boolean values (usefull tu use less memory).
C++ has class (so I can use destructor to automatic deallocation when variable not more needed - usefull for a simpliest usage about variables dinamically allocated).

However I have to say that you make the score about your warnings: Infact, since now, I did a lot of errors (it is the first time I try to use dinamyc allocation and I'm starting to understand pointers only now!) and I had to pain a lot before finding all of them (I write by myself a sort of "debugging code" seeing the fact I don't have a debugger and the fact that I will probably not be able to use gdb - the debugger of gcc).
Now it seems I solved all problems and error into the code writte since now.

---

Strangely, I understand how malloc and realloc works (not calloc, but I inizialize by myself all values) better then how new works, even if new seems simpliest. Don't forget I am more or less a beginner (for example I don't understand how templates woks!) and I must be sure to understand how my code EXACTLY works.
So, for example, If I cannot understand how to use new for allocating memory to a data structure that can increase its size (for example, a database, when I add a new record) I feel better to use malloc/realloc (becouse I know that this line will allocate space for new element without losing data).

I know, reading your explaination, that new doesn't need reallocation becouse it use vectors, but I cannot understand exactly what it means and I cannot see how to do it.
I' sorry if i were not clear...

Hoever can you make a (Simply) example with new to show how it is possible to create a memory allocation that it is "variable" (more or less like using malloc/realloc)?
Last edited on Aug 17, 2008 at 3:48pm
Aug 18, 2008 at 8:20pm
Nobun, it sounds like you are unwilling to learn anything new. You say you use C++ because you know streams better than C I/O. But you use malloc/free because you know them better than new/delete. IMHO, you need to pick a language and learn it. If you are unwilling to learn new/delete, then use C. If you are unwilling to learn fopen, etc, then learn C++. If you are unwilling to learn either, then give up programming, because to be a programmer in any language you have to be willing to learn new things continuously.

new and delete are not magical. To put things in terms of C, you can think of new as malloc() + calling a constructor. You can think of delete as calling a destructor + free(). There isn't much more a beginner needs to know than that.

You really are making more work for yourself by using malloc and arrays than if you were to spend a few hours learning how to use STL vectors, which will manage the memory for you and take care of the "realloc" problem to grow the data structure.

In the long run, you will spend far, far more time debugging memory-related problems that you could have avoided in the first place had you let the STL do the work for you.

PS - I really doubt that you understand completely how malloc works. Have you ever looked at the implementation of malloc?

Now, lastly, if you are truly a beginner wanting to learn from the ground up, fair enough, and I apologize if I came across too strongly. You have to learn how to walk before you can run, I agree.

Aug 19, 2008 at 7:52pm
Don't worry. I appreciate those type of opinions, also becouse are honest.
When I speak to people I like to be honest too.
So I must admit that you are more or less right.
I like to learn more (becouse programming is a hobby I like very much), but in the meantime I have to find the easier and quickier solutions for myself that allow me to undertstand all I do. I also have no much time to spend for my hobby, seeing the fact I have my own duties.
However I understand that probably I will never able to run, however I try to solve all problems I meet step by step.

Backing in the point of your point of view...
I understand that you are talking as a professional programmer (probably it is your work so you can see things that I cannot be able to image) and I understand WHY you suggest to choose plain C or plain CPP.

But let me say only that there isn't any rule that says that CPP programs cannot use also C routines. So I cannot agree with "if you use C-Stile you must use C" seeong also the fact that C has some other limitations (like the fact that you cannot overload functions, nor use classes - I find destructor usefull to deallocate automaticly memory dinamicly allocated).
Also seeing the fact that my project is a two-hand one (even if, since now, all code written is only mine) and my partrner asks me to use C++ (i started in plain C), Plain C is not a choose.

however I don't want to run away far from difficulties and I don't want to find excuses to avoid to learn how to do better my work.
So, if I am able to understand to increase the quality of my code, be sure that I'm not afraid to change my point-of-view. I know that I have A LOT to learn.
This morning, for example, I studied by myslef template functions and I started to understand also them (since yesterday I had no idea how to use them).

Surely you are right when you say that I cannot understand compleatly the use of malloc (and also of new), also becouse I can add that I don't know any concept of assembler. However, and I don't want to seem I'm arguing against you, I have to mark that there are also some expert programmers that thinks that malloc() has a clearer usage than new.

But, saying that, I don't exclude that if I can understand COMPLEATLY how to use new for all situations I need a memory allocation, I'll pass to use ONLY new... but first of all, I have understand all I need. for example, how to do memory re-allocation with new.
In this moment, if I need to modify the size of allocated memory, I know how to do it with malloc/realloc, but not with new. So, when I need a dinamic allocation "resizeable" I use malloc and not new.

But, if you show me a link where to find a desctiption how to use vectors WITH SOME examples (explained), be sure that I'll read it.
Aug 19, 2008 at 8:26pm
I agree -- C and C++ can be intermixed without much worry. No argument there. I just think that if you are going to use C++, then you should spend the time to learn new and delete since they are so fundamental to the object-oriented programming model. malloc() cannot call the constructors on your dynamically allocated objects, so I personally find it almost impossible to write object-oriented code without using new/delete either directly or indirectly (ie, through an STL container). Likewise, free() cannot call the destructors on your dynamically allocated objects either.

For usage information on STL containers, you can reference one of these:
http://www.cplusplus.com/reference/stl/
http://www.sgi.com/tech/stl/

By way of examples, you should be able to find many on the 'net. You keep referring to resizing memory, so I'll give you one example here of that:

So you have an array of integers and you want to add another integer to the array.
In C:

1
2
3
4
5
6
7
8
9
10
11
12
int* integerArray = (int*)malloc( 10 * sizeof( int ) );  // array of 10 ints

// fill up the array...
for( int i = 0; i < 10; ++i )
   integerArray[ i ] = i;

// Now add another one:
integerArray = (int*)realloc( integerArray, 11 );  // array of 11 ints, 1st 10 unchanged
integerArray[ 10 ] = 42;

// And don't forget this:
free( integerArray );


Looks easy, right? This code is fairly simple. But in a large application, the malloc/realloc and free calls might not even be in the same source file. It becomes very hard to prove that the memory is freed when it should be, especially if there is a lot of dynamic memory allocation and deallocation going on (as there is in a large application).

Now let's use a vector to do the same thing (and this isn't even the shortest way to do it):

1
2
3
4
5
6
7
// Create an array of integers:
vector<int>  integerArray;  

// How big is the array?  Well, it currently holds zero integers.  How many can it hold?  
// As many as you can fit in memory.  Let's add a few integers:
for( int i = 0; i < 10; ++i )
    integerArray.push_back( i );


Done. vector<> took care of resizing the memory block for you; you didn't have to worry about it. vector<>'s destructor also took care of freeing the memory when the object was destroyed. You didn't have to worry about that either.

vector<> relieves you from having to worry about the low-level details. It just works. It allows you to focus your attention to the functionality you need to provide.
Aug 20, 2008 at 7:45am
malloc() cannot call the constructors on your dynamically allocated objects, so I personally find it almost impossible to write object-oriented code without using new/delete either directly or indirectly (ie, through an STL container). Likewise, free() cannot call the destructors on your dynamically allocated objects either.

Yes, you are right!
Since now all memory allocation I used is incapsulated in a class and desctructor calls free() routines to deallocate memory when object is killed.
But if I need to a dinamic allocation to an object it is better to use new/delete (using malloc/realloc means you have to declare specific functions to inizialize/terminate class that you must call manually).
I'll read the second link (it seems clearer becouse it has more expplainations). Even if I don't understand how to use it with new, it seems usefull (i donwloaded also stl.zip).


Looks easy, right? This code is fairly simple. But in a large application, the malloc/realloc and free calls might not even be in the same source file. It becomes very hard to prove that the memory is freed when it should be, especially if there is a lot of dynamic memory allocation and deallocation going on (as there is in a large application).

And... isn't the same with new/delete? How can new/delete prove better that the memory is freed when it should be?
Seeing the fact that my application will be a large one, it is for me very important to:
1 - "test" memory usage and see if all goes well
2 - if possible, calculate how many memory I use (also to say in documentation how many memory - more or less - my program requires)


vector<> relieves you from having to worry about the low-level details. It just works. It allows you to focus your attention to the functionality you need to provide.

As I said before, it is very interesting (and thank for your example). However I cannot understand how to use it with new/delete...
I hope to find some examples that shows me how to use Vectors with new...
Aug 20, 2008 at 9:44am
How can new/delete prove better that the memory is freed when it should be?
Because delete calls the destructor which, if written correctly, will free all the memory of the object for you. free() doesn't call anything, and if you need to free() an object which has pointers to other objects, and these objects also have pointers, freeing that becomes nightmarish. It's not hard to make a mistake in this situation, thereby creating a colossal memory leak or, even worse, hundreds of smaller ones.

As I said before, it is very interesting (and thank for your example). However I cannot understand how to use it with new/delete...
You mean you don't how to vector<int> *v=new vector<int>;/*...*/delete v;?
Aug 20, 2008 at 12:46pm
The usage of vector for int, char, float etc is more or less clear thank of the example in the last reply of Jsmith...

But if I have to use new in data structure or in class?

For example if I have a situation like my 1st example (see my first topic)... I know how to do allocation/realloction with malloc(), but how to do it with vector/new?

1
2
3
4
5
6
7
8

//is it right? Should I change something in structure declaration?

A * a;
a = new vector <struct A>

a[ID].b = new vector <struct  B>


And when I have to inizialize an uncertain quantity of class object (and I want to be sure that constructors and destructors are called) it is right an usage like this one?

1
2
MyClass * cl;
cl = new vector < class MyClass >


and when I increase the value of vector will class constructor called for every ID of class or not? And what about calling of class destructor?
Aug 20, 2008 at 1:26pm
No, no, no.
Vectors aren't arrays. You can't declare them like you declare arrays. They're objects in their own right:
1
2
3
4
5
6
7
8
9
std::vector<A> v;
std::vector<A> *v2=new std::vector<A>;
//I prefer to use std::vectors of pointers, so I don't have to write a copy constructor and also to improve performance:
std::vector<A*> v3;
std::vector<A*> *v4=new std::vector<A*>;
//Then to increase the size of the std::vector:
v3.push_back(new A());
//This calls the destructor and deallocates the memory automatically:
v3.pop_back();

Keep in mind that every time the vector needs to be physically resized (there's a virtual size, which you can see, and a physical size, which you can't), every element is copied to a new memory location (there's no realloc() here) and this takes time. But if you use pointers, the vector only needs to copy processor words (the objects pointed to are not copied, obviously), greatly reducing resize time.

Oh, and you don't need to put the class and struct when using templates.
Aug 20, 2008 at 1:31pm

And... isn't the same with new/delete? How can new/delete prove better that the memory is freed when it should be?


No. Look at my second example, and tell me where I used new or delete. You are right that new and delete do not prove anything better than malloc and free. My point with the STL container is that you can avoid the new/delete in the first place. Yes, internally vector is dynamically allocating and freeing memory, but to helios' point, the vector destructor ensures that memory used by the vector is freed.

You are trying to combine vectors with arrays and that makes things hard. You should rarely ever need to dynamically allocate vectors or any other STL container for that matter.

To use your original example:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct C {
   int a, b;
};

struct B {
   std::vector<C> cs;
  // Don't need total_C; use cs.size() to determine number of elements
};

struct A {
  std::vector<B> bs;
  // Don't need total_B; use bs.size() to determine number of elements
};


Done. Memory will be allocated and freed correctly at the right times already, without you having to write a single line of executable code.

Your last example above is wrong because you are confusing vectors and arrays.

 
A* a;


declares the variable "a" to be a pointer to an A. Thanks to C, "a" can also be thought of as an array of A's.

 
new vector<A>();


has type vector<A>*, not A*. Consequently, you would need to declare "a" as

 
vector<A>* a = new vector<A>();


Here is the correct way:

1
2
3
A a;
a.bs.push_back( B() );   
a.bs.back().push_back( C() ); 


The first line of code declares a variable of type A.
The second line adds a new B to the end of A's "array".
The third line accesses the last element of A's "array" and adds a new C to it.

Aug 20, 2008 at 3:34pm
Helios, Jsmith... at a first-eye I'm not sure I understand all you said. I'll read all carefully and if, after a deep read (i need at least 1-2 days), some doubts remain I'll post specific questions.

In the meantime thank to all of you (hoping to don't bother you with my next questions - I'm almost sure I'm not able to understand all by myself about vector usage).
Topic archived. No new replies allowed.