wilson@brillig.cs.umd.edu (09/27/90)
Am I right that there is no way to vary a parameter to a constructor for a class object having global scope without recompilation? I would like to vary the seed to an object which is a random number generator used by several different objects (which is why it is global). Currently the seed must be hard coded since my tests show that the constructor is invoked before main is executed. I am using g++, the GNU C++ compiler. For that matter, is there anything special about having a global class object? I have code which runs properly when class objects are declared within main, but when I move them up above main the code crashes from within the constructor for the first object. Actually the code crashes after trying to free up heap space used for constructing a char* within the constructor. I'm just generally puzzled about execution of code before main in invoked. Apparently, I can't count on all necessary system initializations being performed before my constructors are called. Does anyone have any insights to this issue? Anne Wilson
jbuck@galileo.berkeley.edu (Joe Buck) (09/27/90)
In article <26729@mimsy.umd.edu>, wilson@brillig.cs.umd.edu writes: > Am I right that there is no way to vary a parameter to > a constructor for a class object having global scope > without recompilation? Well, since the constructor is invoked before main(), you couldn't influence its arguments by means of command-line parameters. I suppose you could use environment variables though: class RNG { public: RNG(int seed); private: ... whatever } RNG globalGenerator(atoi(getenv("SEED"))); which of course would blow up if SEED were not defined. I don't recommend this! |> Currently the seed must be hard coded since my tests show |> that the constructor is invoked before main is executed. This is a feature of the language. > For that matter, is there anything special about having a global > class object? I have code which runs properly when class objects > are declared within main, but when I move them up above main > the code crashes from within the constructor for the first object. This is probably an order-of-constructors problem. For example, if you try to do stream I/O from constructors with g++ and libg++ you'll get a crash when trying to construct a global object because the constructor will be called before cin, cout, or cerr is constructed. > Actually the code crashes after trying to free up heap space used > for constructing a char* within the constructor. > I'm just generally puzzled about execution of code before main > in invoked. Apparently, I can't count on all necessary > system initializations being performed before my constructors > are called. This is a libg++ problem, though it can bite users of cfront in some situations as well. I've worked around the problem by modifying gnulib3.c to call global constructors in reverse order (so libraries will be initialized before your code). You can also work around the problem by making sure your .o files are handed to the linker in an order that works (constructors are called in the order that the .o files are given to the linker). -- Joe Buck jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck
glenn@huxley.huxley.bitstream.com (Glenn P. Parker) (09/27/90)
In article <26729@mimsy.umd.edu> wilson@brillig.cs.umd.edu writes: > Am I right that there is no way to vary a parameter to > a constructor for a class object having global scope > without recompilation? I don't know about g++, but C++ allows you to initialize a global object using a function call. A function for a random seed might query the O.S. for the time, or some such value. Of course, you should not rely on facilities like the streams library during this initialization, since they require some initialization of their own. An alternative (if the previous suggestion is not supported in g++) would be to declare a global pointer to an object that is constructed in main(). -- Glenn P. Parker glenn@bitstream.com Bitstream, Inc. uunet!huxley!glenn 215 First Street BIX: parker Cambridge, MA 02142-1270
steve@taumet.com (Stephen Clamage) (09/27/90)
wilson@brillig.cs.umd.edu writes: >Am I right that there is no way to vary a parameter to >a constructor for a class object having global scope >without recompilation? I would like to vary the seed >to an object which is a random number generator used by >several different objects (which is why it is global). >Currently the seed must be hard coded since my tests show >that the constructor is invoked before main is executed. >I am using g++, the GNU C++ compiler. >For that matter, is there anything special about having a global >class object? I have code which runs properly when class objects >are declared within main, but when I move them up above main >the code crashes from within the constructor for the first object. >Actually the code crashes after trying to free up heap space used >for constructing a char* within the constructor. There is a slightly ugly but very portable technique to handle global objects, which are slightly special. It is used in the iostreams library to get the standard streams initialized at the right time. NOTE: The word "static" has two meanings in C and C++: It means having the lifetime of the program (non-auto), and it also means not externally declared/defined (non-extern). We need to use the word in both meanings here. I will qualify the word each time. Within a compilation unit, static (non-auto) objects are created in the order they are declared in the text, and destroyed in the reverse order. There is no portable way to guarantee the order of initialization of objects in different compilation units within a program. (Another poster mentioned that initialization occurs in the order in which the modules are linked. This may be true on some systems, but is by no means guaranteed.) So we define an initializer class and a static (non-extern) instance of the class in the class header which is included in every compilation unit which needs to know about the class. The class constructor has a "one-time switch" to insure the body is executed only once. file "myclass.h" ================ class myclass { .... }; class myclass_init { static int count; public: myclass_init(); ~myclass_init(); }; static myclass_init mi; ================ file "myclass.c" ================ #include "myclass.h" ... // myclass member functions myclass_init::count = 0; // static member initialization // this constructor will be executed before any other constructors in // any modules which include "myclass.h" myclass_init::myclass_init() { if( ++count == 1 ) { // one-time processing here } } // this destructor will be executed after all other destructors in // any modules which include "myclass.h" myclass_init::~myclass_init() { if( count-- == 1 ) { // one-time processing here } } ================ ================ A similar technique can be used to get exactly one object of a given type statically constructed conceptually before main begins. file "myclass.h" ================ class myclass { ... public: myclass(); }; class myclass_init { public: myclass_init(); }; static myclass_init mi; extern myclass *my; // we want exactly one of these statically constructed ================ file "myclass.c" ================ #include <myclass.h> ... // myclass member functions myclass my = 0; // defining instance of mi set to 0 myclass_init::myclass_init() { if( ! my ) { my = new myclass(); // gets constructed exactly once ... // other processing } } ================ ================ As long as myclass.h is included in a file before any reference to anything which depends on what it does, the static construction will have occurred first. -- Steve Clamage, TauMetric Corp, steve@taumet.com
roman@sparc17.hri.com (Roman Budzianowski) (09/28/90)
In article <28241@pasteur.Berkeley.EDU>, jbuck@galileo.berkeley.edu (Joe Buck) writes: > You can also work around the problem by making sure your .o files > are handed to the linker in an order that works (constructors are > called in the order that the .o files are given to the linker). > > > -- > Joe Buck > jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck In cfront from SUN w/munch, the constructors are called in reverse alphabetic order determined by file names.
hall@eclipse.stanford.edu (Keith Hall) (10/02/90)
In article <28241@pasteur.Berkeley.EDU> jbuck@galileo.berkeley.edu (Joe Buck) writes: > >In article <26729@mimsy.umd.edu>, wilson@brillig.cs.umd.edu writes: >> I'm just generally puzzled about execution of code before main >> in invoked. Apparently, I can't count on all necessary >> system initializations being performed before my constructors >> are called. > >This is a libg++ problem, though it can bite users of cfront in >some situations as well. I've worked around the problem by >modifying gnulib3.c to call global constructors in >reverse order (so libraries will be initialized before your code). >You can also work around the problem by making sure your .o files >are handed to the linker in an order that works (constructors are >called in the order that the .o files are given to the linker). Having the constructors called in the proper order seems so fundamental that I don't understand why that behavior is not already ensured by the compiler/linker. Buck, can your mods to gnulib3 become a standard part of libg++? Keith
ark@alice.att.com (Andrew Koenig) (10/03/90)
In article <1990Oct2.162451.3101@Neon.Stanford.EDU>, hall@eclipse.stanford.edu (Keith Hall) writes: > Having the constructors called in the proper order seems so > fundamental that I don't understand why that behavior is not already > ensured by the compiler/linker. What is the proper order? How can a compiler determine what that order is? -- --Andrew Koenig ark@europa.att.com
andru@proton.lcs.mit.edu (Andrew Myers) (10/05/90)
In article <11427@alice.att.com> ark@alice.att.com (Andrew Koenig) writes: >In article <1990Oct2.162451.3101@Neon.Stanford.EDU>, hall@eclipse.stanford.edu (Keith Hall) writes: > >> Having the constructors called in the proper order seems so >> fundamental that I don't understand why that behavior is not already >> ensured by the compiler/linker. > >What is the proper order? How can a compiler determine what >that order is? With a small amount of work, it's possible to create a class which orders global constructors (and other operations to be performed before main) based on a dependency graph. Similarly, the same technique can be used to unwind the process and do ordered global destruction, if desired. Andrew