vaughan@puma.cad.mcc.com (Paul Vaughan) (06/28/90)
Newsgroups: gnu.g++ Subject: libg++ usage --text follows this line-- In libg++ (the c++ library of classes and parameterized classes distributed with gnu c++), there is a parameterized class known as SLList that implements a simple linked list data structure. To create an instance of a parameterized class such as SLList, one uses genclass-- a simple tool that replaces type place holders in a prototype class definition with a real type name. I use a lot of SLList's from libg++ that all hold simple pointers. However, instead of genclassing a new SLList type for each pointer type, I genclass one voidpSLList and then implement lists for other classes by making a simple interface file that casts the arguments of input and output functions to the appropriate pointer type. For instance: (Note the following excerpt could probably be considered a Derived Work of libg++ and thereby fall under the GPL. This is just an excerpt, however--consider it a quote with words changed, added, and removed. (kinda silly, huh? :-/)) #include <voidp.SLList.h> class Foo; typedef Foo* Foop; class FoopSLList { protected: voidpSLList l; public: FoopSLList() {}; FoopSLList(FoopSLList& a) : l(a.l) {}; . . . void join(FoopSLList& sl) { l.join(sl.l); }; Foop& operator () (Pix p) { return (Foop&) l(p); }; . . . This works out fairly well. All the functions for FoopSLList are defined inline and the whole thing adds about 150 bytes to a .o file when it is included in the source, above the cost of including a normal Foop.SLList.h. So I pay a small price for the explicit conversions, have only one full implementation of voidpSLList, eliminate a lot of .cc and .o files. Plus, making a new one just involves creating one new file and doesn't require modifying the Makefile. It also collects all the casting into one place where it's straightforward to verify that it is correct. It adds up to a significant savings by eliminating many Class.SLList.o files from the executable. So, I thought I'd apply this technique to Maps and Plex's and Queues, etc. This did not work out because these classes in libg++ all have virtual functions. It turned out that replacing two Plex (generic class interface definition with no implementation) and XPLex (an implementation) types both holding simple class specific pointers with one voidpPlex and voidpXPlex and four simple conversion .h files increased my executable size dramatically (over 1 MegaByte!), because of the proliferation of virtual function tables. So, I'm just offering this bit of experience to the pool, with the hope of gaining a better understanding from any followup discussion. Comments: I've never quite understood why these classes should have virtual functions (or be split into two classes, eg. Plex and XPlex). I've never had an occassion to use a FoopPlex* instead of a FoopXPlex*. It's generally pointless to write code that's completely independent of the implementation, because it usually has to arrange for the creation of the thing, and thus know exactly what type it is anyway--so the .h file is necesarily already included. The .h file and virtual function table explosion problem has almost led me to stop using direct instances of objects such as these in classes. For instance instead of #include <Foop.VHMap.h> class Bar { protected: FoopVHMap map; ... I'm tempted to use class FoopVHMap; class Bar { protected: FoopVHMap& map ... and arrange for the reference initialization and destruction in the constructors and destructors. This is not as convenient, and does more dynamic memory allocation (of smaller pieces) and so seems kind of silly, but I expect it to help the modularity problem. Any thoughts on this? Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639 Box 200195, Austin, TX 78720 | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan