Click to See Complete Forum and Search --> : STL list with Complex Datatype


ChadS1
January 28th, 2005, 03:46 AM
I am using the stl list class for a class and not a simple type. As a result, I'm having a hard time deciding what copy constructors and deconstructors I need and whether calling list.clear will release all the associated memory. Here are the specifics:

class ReadData {
int nOffset;
string sPath;
};


list<ReadData>ReadList;

Then Say I have the following function, which is called repeatedly:

void AddRead(int nOffset, char * sPath) {
ReadData rd;
rd.nOffset = nOffset;
rd.sPath = sPath;
ReadList.push_back(rd);
}


I have a number of questions regarding this scenario. Will ReadList have trouble when rd goes out of scope? I guess this depends on how rd is added to the list and what the default copy constructor will do. Will the default copy constructor basically do nOffset = rd.nOffset; sPath = rd.sPath, the later statement calling the string's operator= making a deep copy. Or will a shallow copy be made, but when rd goes out of scope, because I have provided no destructor, the shallow copy of rd added to ReadList will still be valid. I suspect the later to be true.

Next, say after adding a bunch of ReadData nodes to the list I call ReadList.clear(). What will happen? Will the allocated memory be effectively freed? Would ReadList.clear() even free the memory associated with the rd objects or would it just free the memory associated with making the linked list, but leave the memory associated w/ the ReadData objects? Say ReadList.clear() does call the nodes' ReadData destructor, would the string object be properly freed without ReadData having a destructor?

Basically I'd like to know what I need to do to this code to make it not have a memory leak while trying to keep it as efficient as possible by using shallow instead of deep copies where permissible. I suspect I'll need a copy constructor and destructor for the ReadData class, but will I also need an operator= function as well?

Much Thanks,
- Chad

Paul McKenzie
January 28th, 2005, 05:29 AM
I am using the stl list class for a class and not a simple type. As a result, I'm having a hard time deciding what copy constructors and deconstructors I need and whether calling list.clear will release all the associated memory.To cut to the chase, there is no need for coding any copy constructors or destructors for your class.

All the members are copyable, assignable, and destructable (int, std::string). Once you have this, there are no problems storing such a class in a list. If it were, then std::list would be IMO piece of junk that no programmer would or should use.
Will ReadList have trouble when rd goes out of scope?No. A std::list stores a copy of the data you place in the list.
Will the default copy constructor basically do nOffset = rd.nOffset; sPath = rd.sPath, the later statement calling the string's operator= making a deep copy.This is the case for any class or struct -- a member-wise copy is done when you copy/assign an object to another object.
Next, say after adding a bunch of ReadData nodes to the list I call ReadList.clear(). What will happen? Will the allocated memory be effectively freed?Yes, if not, std::list would be a horribly deficient class that no programmer would be willing to use.Would ReadList.clear() even free the memory associated with the rd objects or would it just free the memory associated with making the linked list, but leave the memory associated w/ the ReadData objects?The copies are destroyed, the link list is destroyed. There is nothing else you need to do.Say ReadList.clear() does call the nodes' ReadData destructor, would the string object be properly freed without ReadData having a destructor?Yes, the destructor is called. What happens here?

int main()
{
ReadData r;
}

What happens at the end of this program? Is the string destructor called? Yes it is.
Basically I'd like to know what I need to do to this code to make it not have a memory leak while trying to keep it as efficient as possible by using shallow instead of deep copies where permissible.There are no memory leaks. The class you posted has copyable and assignable members. I suspect I'll need a copy constructor and destructor for the ReadData class,You suspect wrong.but will I also need an operator= function as well?No.

Basically, the trick is this: Does the object that you are planning to place in the std::list behave correctly for this simple program?

int main()
{
MyObject a;
// assume a has some data
//...
MyObject b;
a = b;
MyObject c = a;
}

You have three objects, a, b, and c. They are being copied, assigned, and destroyed. If this program behaves correctly without a memory leak, crash, whatever, then MyObject is safely copyable and assignable. Therefore MyObject objects can be safely placed in a list, vector, or any other STL container.

Objects that are not safely copyable are ones that contain pointers to dynamically allocated memory, and there is no user-defined copy constructor or assignment operator, or destructor to take care of the act of copying and deleting memory.

Another case is where an object has members that are some sort of resource (a FILE handle for example), and copying these objects may cause some issues, since you'll have two (or more) FILE handle's (for example), and destroying such objects may cause you to do two or more destructions of the same handle.

The other case is that std::auto_ptr cannot be stored in STL containers for reasons that have been explained here many times.

Regards,

Paul McKenzie

NMTop40
January 28th, 2005, 09:42 AM
The best type for any collection is boost::shared_ptr< T > where T is your type.

So std::list< boost::shared_ptr< T > >

Now you do not have to worry about deallocating the objects when they are removed from your list.

ChadS1
January 28th, 2005, 06:55 PM
Thanks for the feedback guys. Paul, your explanation makes everything intuitive. I remember learning that the default copy constructor is a bitwise copy, but I was unsure if that meant member-wise as well, so now I know.

Thanks again.
- Chad