Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!radar!cadillac!vaughan@mcc.com From: vaughan@mcc.com (Paul Vaughan) Newsgroups: comp.lang.c++ Subject: Re: problems with calling streams from constructors Message-ID: <10508@cadillac.CAD.MCC.COM> Date: 17 Aug 90 14:32:41 GMT References: <38170@ucbvax.BERKELEY.EDU> <1990Aug15.224436.10176@cs.columbia.edu> Sender: news@cadillac.CAD.MCC.COM Reply-To: vaughan@mcc.com (Paul Vaughan) Organization: MCC VLSI CAD Program Lines: 81 In-reply-to: kearns@cs.columbia.edu (Steve Kearns) Here is an idea for assuring static object intialization prior to use that can work for streams implementation (particularly libg++). I've done this sort of thing for my own classes occasionally, and I think I may have suggested it to Doug Lea for libg++, but I'm not sure. The code here is oriented toward the libg++ stream implementation. One way it might be done is this. Toward the end of stream.cc, insert //#include //add this so this fragment will actually compile class CoutHolder { public: ostream* coutp; CoutHolder() : coutp(0) {}; ~CoutHolder() { delete coutp; } }; static CoutHolder coutHolder; //will provide for destruction of cout. extern ostream* _coutp_; ostream* _coutp_ = _coutp_ ? (coutHolder.coutp = _coutp_ ) : (coutHolder.coutp = new ostream(3)); // fill in more appropriate args for the ostream constructor. //----------------------- // In stream.h extern ostream* _coutp_; static ostream& mycout = _coutp_ ? *_coutp_ : *(_coutp_ = new ostream(3)); //mycout should be named cout--I renamed it so this would compile. The point of the CoutHolder is to get the cout stream destructed as it currently is. This is the enabling rule: The language guarantees you that any external global variables (such as the ostream& _coutp_) will either have been initialized or will be 0 during module intialization, regardless of the order. If the stream.o module gets intialized first, it will find _coutp_ = 0 and will allocate a new one, recording it in the holder for later destruction. Then other modules will find _coutp_ already initialized and will just keep the one that's aready there. But if some other module is intialized first, it will find that _coutp_ = 0 and so it will allocate a new one and record it in the _coutp_ variable. Then when the stream.o module is initialized, it will find _coutp_ !=0 and so will not make a new one but will record the existing one in the holder for later destruction. Notes: If you could count on the address of an unitialized reference being 0, you might be able to eliminate the _coutp_ global variable. As I've written it, you couldn't include stream.h in stream.cc, which is kind of unhandy. You might protect the stuff that I'm adding to stream.h with a #ifndef and define a symbol in stream.cc so that those lines wouldn't get into stream.cc. Since the CoutHolder class definition doesn't go into a .h file, nobody else sees it, so it doesn't clutter things up. Of course, stream.h must be protected against multiple inclusions, but I'm sure it already is. cout must be static, because it will be declared and initialized in many different modules. This has the interesting and possibly undesirable property that cfront will warn if you include stream.h but then don't use cout. There's probably a simple way to get around that though. I've used this sort of technique before for intializing lists of objects created at the file scope in different modules. 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