Is this good form?
-
Hello everyone, I have been working on an MFC SDI program whose Document actually has lists of lists (and possibly a list of a list of a list). I would like to get into a good habit and be consistent with the way I maintain collections (mostly lists, occasionally arrays and maps). Almost all my objects are derived from CObject (for serializing, etc.). I guess it comes down to picking between CList, CList, CList and whatever other combinations. To keep sane, I think I always want to use CList. That way, I just use the new operator at the point where an object needs to be instantiated and call delete on it (while traversing the list or sublist) at the 'outer' list's destructor. I would like comments about this. Is it safe? Is it a decent practice to keep? How can I prevent double deleting the same objects (if that could even happen)? Does this choice affect how I code the required copy constructor and assignment operator (which always seem to involve references)? Thanks in advance for any advice and comments! Eric
-
Hello everyone, I have been working on an MFC SDI program whose Document actually has lists of lists (and possibly a list of a list of a list). I would like to get into a good habit and be consistent with the way I maintain collections (mostly lists, occasionally arrays and maps). Almost all my objects are derived from CObject (for serializing, etc.). I guess it comes down to picking between CList, CList, CList and whatever other combinations. To keep sane, I think I always want to use CList. That way, I just use the new operator at the point where an object needs to be instantiated and call delete on it (while traversing the list or sublist) at the 'outer' list's destructor. I would like comments about this. Is it safe? Is it a decent practice to keep? How can I prevent double deleting the same objects (if that could even happen)? Does this choice affect how I code the required copy constructor and assignment operator (which always seem to involve references)? Thanks in advance for any advice and comments! Eric
Cloaca wrote: To keep sane, I think I always want to use CList. MFC containers are utter crap. Use std::list instead and you'll find a lot of the ancillary code you need to write will already be there for you. Christian I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
-
Cloaca wrote: To keep sane, I think I always want to use CList. MFC containers are utter crap. Use std::list instead and you'll find a lot of the ancillary code you need to write will already be there for you. Christian I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
Thanks for your tip Christian. I will look around to learn how to make std::list (part of the STL, right?) work with MFC (including topics like Serialization, etc.). If you could suggest any resources in particular, that would be great. Thanks again! :-) Eric
-
Hello everyone, I have been working on an MFC SDI program whose Document actually has lists of lists (and possibly a list of a list of a list). I would like to get into a good habit and be consistent with the way I maintain collections (mostly lists, occasionally arrays and maps). Almost all my objects are derived from CObject (for serializing, etc.). I guess it comes down to picking between CList, CList, CList and whatever other combinations. To keep sane, I think I always want to use CList. That way, I just use the new operator at the point where an object needs to be instantiated and call delete on it (while traversing the list or sublist) at the 'outer' list's destructor. I would like comments about this. Is it safe? Is it a decent practice to keep? How can I prevent double deleting the same objects (if that could even happen)? Does this choice affect how I code the required copy constructor and assignment operator (which always seem to involve references)? Thanks in advance for any advice and comments! Eric
It depends whether you want homogeneous (containing one type of object only) or heterogeneous (containing multiple types of object) containers. If I want a homogeneous container, I typically have the container manage the storage of the contained objects. If the objects are small (perhaps
int
s), I use a CList< int, int >. If the objects are larger than about 8 bytes, I use CList< T, const T& > so that any functions which need an object (to store it, or compare it) take their argument by constant reference. You don't need to do any extra clean-up when you destroy the container; it destroys all the elements for you. For a concrete definition of a heterogeneous container, consider a class hierarchy modelling shapes. We have an abstract base classCShape
with derived classesCRectangle
,CEllipse
andCPolygon
(for example). We want the container to be able to hold any combination of rectangles, ellipses, polygons and whatever else we might define in future. To get polymorphic behaviour, we must store base class pointers. So I would normally declare the container as storing pointers of the type of the most-derived base class common to the elements to be contained. In this case I would use aCList< CShape*, CShape* >
. The ARGTYPE is aCShape*
because pointers are trivial to copy. Lists of lists are tricky in MFC because CList doesn't define a copy constructor or assignment operator. You can't contain a CList inside a CList (although you can store CList pointers). If the top-level list is heterogeneous, you probably do need to use a list of CObject pointers, and MFC has a special class for that: CObList. -
It depends whether you want homogeneous (containing one type of object only) or heterogeneous (containing multiple types of object) containers. If I want a homogeneous container, I typically have the container manage the storage of the contained objects. If the objects are small (perhaps
int
s), I use a CList< int, int >. If the objects are larger than about 8 bytes, I use CList< T, const T& > so that any functions which need an object (to store it, or compare it) take their argument by constant reference. You don't need to do any extra clean-up when you destroy the container; it destroys all the elements for you. For a concrete definition of a heterogeneous container, consider a class hierarchy modelling shapes. We have an abstract base classCShape
with derived classesCRectangle
,CEllipse
andCPolygon
(for example). We want the container to be able to hold any combination of rectangles, ellipses, polygons and whatever else we might define in future. To get polymorphic behaviour, we must store base class pointers. So I would normally declare the container as storing pointers of the type of the most-derived base class common to the elements to be contained. In this case I would use aCList< CShape*, CShape* >
. The ARGTYPE is aCShape*
because pointers are trivial to copy. Lists of lists are tricky in MFC because CList doesn't define a copy constructor or assignment operator. You can't contain a CList inside a CList (although you can store CList pointers). If the top-level list is heterogeneous, you probably do need to use a list of CObject pointers, and MFC has a special class for that: CObList.Hi Mike, I appreciate your response. From what you wrote it looks like if I need to maintain a collection of different objects (but all derived from a common base), then a CList< baseclass*, basclass*> is the way to go (which is what I had been thinking for 'my sanity's sake'). For trivially small things (e.g. ints), a CList is good. This sounds good to me. You wrote: "If the objects are larger than about 8 bytes, I use CList< T, const T& > so that any functions which need an object (to store it, or compare it) take their argument by constant reference." What is the advantage of doing CList over CList ? Or, alternatively, is there a reason not to do CList all the time? Thanks again! Eric
-
Hi Mike, I appreciate your response. From what you wrote it looks like if I need to maintain a collection of different objects (but all derived from a common base), then a CList< baseclass*, basclass*> is the way to go (which is what I had been thinking for 'my sanity's sake'). For trivially small things (e.g. ints), a CList is good. This sounds good to me. You wrote: "If the objects are larger than about 8 bytes, I use CList< T, const T& > so that any functions which need an object (to store it, or compare it) take their argument by constant reference." What is the advantage of doing CList over CList ? Or, alternatively, is there a reason not to do CList all the time? Thanks again! Eric
I prefer the version without the pointers for three reasons:
- I don't have to clean up the list myself (CList doesn't delete objects pointed to in the destructor).
- I don't have to handle indirections.
- The list has less memory-management overhead.
I'll deviate from this if I have to store references to the same object in multiple places in a list, but this is less common.
-
I prefer the version without the pointers for three reasons:
- I don't have to clean up the list myself (CList doesn't delete objects pointed to in the destructor).
- I don't have to handle indirections.
- The list has less memory-management overhead.
I'll deviate from this if I have to store references to the same object in multiple places in a list, but this is less common.
Hi Mike, Thanks again. About reason 1.: Most times, the objects that are in a list are made using a call to 'new' at some point in the code. If this is the case, then the contents of the list (the newed objects) need to get deleted at some point anyway. And this must be done by walking through the list in a loop to call delete for each item before doing a RemoveAll() on the list. Or, do you have a methodology in coding that 'recycles' objects. That is, a variable of type CMyObject is declared and reused (has its data changed) whenever an item needs to be added to the list. Then, due to storing actual T's (not T*'s or T&'s), they are passed by reference into the CList by value (so that the declared variable can be changed for reuse to create the next item in the list). Is this what you mean? Does this mean that the destructor for each item in the list is called when the CList is destroyed? Thanks very much, Eric