Skip to main content
gamedev.net
🔒 Locked

doubt about memory

Started by MaxDemian 13 replies 1.4k views
Original Post
MaxDemian
MaxDemian
Hi, I want to know something about memory. If I declare something like this:

struct sData
{
int i;
char a[15];
};

sData * pData = new sData();


and then I free memory like this:

delete pData;

All right until this point. But If I have this:

struct Node 
{
    sData * pD;//This is a pointer that store a dynamic declariton of a sData object
    Node * next;
};

Node * pNode = new Node();

If i want to free memory and do this:

delete pNode;

Im also freeing pD pinter? Thanks ;)
Zipster
Zipster
Quote:
Original post by MaxDemian
But If I have this:

*** Source Snippet Removed ***

If i want to free memory and do this:

*** Source Snippet Removed ***

Im also freeing pD pinter?

Thanks ;)

No. It just frees the storage for the pointer itself, not what the pointer points to. The proper way to do this and free what the pointer points to would be to create a destructor for your struct and have it delete the memory.
MaxDemian
MaxDemian
OK, but if I want to implement the struct like this:

template <typename T,bool dupe>class cDoubleLinkedList{protected:        struct Node        {                T  data;                struct Node *next;                struct Node *prev;                Node(){}                ~Node(){delete data;}        };        typedef struct Node * PNode;...};


The compiler said that data must be pointer here:

~Node(){delete data;}


So.. What can i do here?
Drew_Benton
Drew_Benton
Quote:
Original post by MaxDemian
OK, but if I want to implement the struct like this:

*** Source Snippet Removed ***

The compiler said that data must be pointer here:

*** Source Snippet Removed ***

So.. What can i do here?


Right now you have T data; which is an actual object that will be allocated on the stack. If you wanted to delete data;, it should read T * data;, which would declare data as a pointer to a type of T.
Treb
Treb
Though if you keep T as an object, not a pointer, it will remove itself without delete. You only need to "delete" things you created with "new".
MaxDemian
MaxDemian
Quote:
Original post by Treb
Though if you keep T as an object, not a pointer, it will remove itself without delete. You only need to "delete" things you created with "new".


Yep, but the problem is that sometimes T is sData*

I mean
cDoubleLinkedList<sData*,false> MyList;



in that case I have to remove it I think.

Any way... What happend if I do this in the destructor:
~Node(){delete &data}

??
Sc4Freak
Sc4Freak
No. Since T (from your point of view) is not dynamically allocated, it isn't your responsibility to delete it. If the user of your class decided to make T an sData*, then it's his responsibility to ensure that the memory gets freed, not yours.
iMalc
iMalc
Quote:
Original post by MaxDemian
Any way... What happend if I do this in the destructor:
*** Source Snippet Removed ***
??
For starters, then you'd have problems when T is a pointer.

Basically it's not the right solution. You could (I think) instead specialise for pointer and non-pointer types, or you could use a compile-time if-statement through template-meta-programming. No doubt something from boost would do the trick.
Wolfdog
Wolfdog
Quote:
Original post by MaxDemian
Any way... What happend if I do this in the destructor:
*** Source Snippet Removed ***
??


Most likely the behavior is undefined, but on most platforms you will experience a crash in the memory routines called by the standard delete procedure. The pointer you are passing in is not a pointer returned by new so this means when you pass it to delete it will try to work with memory that is not structured as expected.

In the case of...
cDoubleLinkedList<sData*,false> MyList;

What you end up passing into delete is a pointer to where a pointer is stored

In the case of...
cDoubleLinkedList<sData,false> MyList;

What you end up passing into delete is a pointer to data within a Node structure (technically because T data is the first member you might just pass in a pointer to the beginning of the Node structure which has already started destruction and you would be deleting it twice.)

To actually put objects into this list...
cDoubleLinkedList<sData*,false> MyList;

The new operator must be used to create the objects first. The list does not create the objects that the sData* pointer is pointing to so that makes it the callers responsibility to create them. That means it is the callers responsibility to delete every pointer in that list before the list is deleted, that could happen in the destructor for a class containing the list.

Every new must have a matching delete, and only one delete for every new (you can call delete repeatedly on a null pointer but that is not really important here.)

To sum up remove the delete call in the Node destructor.
Zahlman
Zahlman
1) You have a question, not a "doubt". Just FYI.
2) Proper memory management is hard. You should consider using more sophisticated tools.
3) Creating your own doubly-linked list is a fantastic way to waste time. It already exists in the standard library: std::list, from .
MaxDemian
MaxDemian
Quote:
Original post by Sc4Freak
No. Since T (from your point of view) is not dynamically allocated, it isn't your responsibility to delete it. If the user of your class decided to make T an sData*, then it's his responsibility to ensure that the memory gets freed, not yours.


mm but what about if If I do this:

cDoubleLinkedList<sData*,false> MyList;sData * data = new sData();MyList.Add(data);


In this case is dynamically allocated?

So I have to use delete?

Quote:
Original post by Zahlman
3) Creating your own doubly-linked list is a fantastic way to waste time. It already exists in the standard library: std::list, from .


Yes, I know that, but I have to do my own list for university purposes.

Well I will use T data as T * data. Thanks all ;)

[Edited by - MaxDemian on October 6, 2008 8:33:36 AM]
Wolfdog
Wolfdog
Quote:
Original post by MaxDemian
Well I will use T data as T * data. Thanks all ;)
No! That will only work if you are calling new in your Add function for the passed in pointer. In which case you have not solved anything because the caller will still need to delete their own memory. Use T data and remove the delete from the Node destructor.

The way your list will be used by someone else.
cDoubleLinkedList<sData*,false> MyList;sData * data1 = new sData();sData * data2 = new sData();sData * data3 = new sData();MyList.Add(data1);MyList.Add(data2);MyList.Add(data3);// Code using MyList// A for loop using an iterator could be used here if your list supports itwhile(MyList.size() != 0){  // Some way to grab one of the entries  sData * temp = MyList.front();  MyList.pop_front();  delete temp;}

Assuming you are not calling new in your add function your program will crash with the above example, your example above that and the next example. If you just use T data it will all work.

cDoubleLinkedList<sData*,false> MyList;sData data1;sData data2;sData data3;MyList.Add(data1);MyList.Add(data2);MyList.Add(data3);// Code using MyList

I don't know why you are trying to delete the memory for the caller. If you think it's because you have to, you are incorrect. If you think it will make life easier for the caller, you are also incorrect.
MaxDemian
MaxDemian
Quote:
Original post by Wolfdog
Quote:
Original post by MaxDemian
Well I will use T data as T * data. Thanks all ;)
No! That will only work if you are calling new in your Add function for the passed in pointer. In which case you have not solved anything because the caller will still need to delete their own memory. Use T data and remove the delete from the Node destructor.

The way your list will be used by someone else.*** Source Snippet Removed ***
Assuming you are not calling new in your add function your program will crash with the above example, your example above that and the next example. If you just use T data it will all work.

*** Source Snippet Removed ***
I don't know why you are trying to delete the memory for the caller. If you think it's because you have to, you are incorrect. If you think it will make life easier for the caller, you are also incorrect.


OK and If I use T data, who free memory when my list store pointers? because the data of my list will be a pointer to other element in other list. Will it be freeing itself?
rip-off
rip-off
The simplest solution is to follow the standard library: all standard containers only manage the memory they request. If you store pointers in a standard container, you are then responsible for memory management. Through the use of smart pointers, you can then completely automate memory manangement. For example, consider std::vector< boost::shared_ptr >.

One important issue should you decide your container owns any pointers it contains is where the pointers come from. Consider also that not all pointers can be safely deleted. What about:
- Stack values (*) and other weak pointers
- new [] Arrays (which must be be deallocated with delete [])
- Pointers from malloc()
- API pointers (which may have a function in the library to free the memory)

The point being, just because someone puts pointers in your container doesn't mean they are candidates for deletion.

* Although generally you would shy away from storing pointers to stack objects in a container, for local use there can be applications for this.
Zahlman
Zahlman
Quote:
Original post by MaxDemian
OK and If I use T data, who free memory when my list store pointers?


Whoever put the pointers into the list. The container can't possibly know whether those pointers point at dynamically allocated stuff, or pre-existing elements in another list, or any number of other things. The responsibility goes with the code that actually has knowledge.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.