[comp.lang.c++] Initializing static area of classes....

nsundare@copper.ucs.indiana.edu (Neelakantan Sundaresan) (03/05/91)

I am trying to solve the problem of initializing the static(shared) data
area of a class type. Basically I would like this initializtion and any
other house keeping stuff done, when the first object instance of that
class is 'construct'ed. Is there a neat way to achieve this?

What I have been doing is define a global variable of that class, whose
constructor is different from any others for that class (in the sense of
number or types of parameters it takes) and in the code for this
constructor do the initialization.  

I guess this is not a very clean way to do it,
Is there a better way to solve this....

Thanks for any ideas,

Neel Sundaresan
(A C++ novice)

wlp@calmasd.Prime.COM (Walter L. Peterson, Jr.) (03/08/91)

In article <1991Mar4.224519.6434@bronze.ucs.indiana.edu> nsundare@copper.ucs.indiana.edu (Neelakantan Sundaresan) writes:
>
>I am trying to solve the problem of initializing the static(shared) data
>area of a class type. Basically I would like this initializtion and any
>other house keeping stuff done, when the first object instance of that
>class is 'construct'ed. Is there a neat way to achieve this?
>

There is no "neat" way to do this. There is, however, "A" way to do
this. What you need to do is create yet another class, not a special
constuctor.  If your class is called Foo, lets call this new class
Foo_Starter:

    // declare clas Foo here

    class Foo {
      static whatever;
    };


    class Foo_Starter {
      static count;
    public:
      Foo_Starter() {
        if (count++ == 0) {
          whatever = 33;   // initialize Foo's static data members
        }
      }

      ~Foo_Starter() {
        if (--count ==0) {
          // clean up Foo's statics ( if necessary )
        }
      }
    };

    static Foo_Starter startfoo;


Put these declarations and definitions in the same header file. When
that header file's code is encountered for the first time during
execution, the static instance of Foo_Starter will be constructed. The
static data member count in Foo_Starter will have been initialized to
zero.  By the language definition of C++ statics, unlike all other
type of objects, ARE initialized to zero.  The constructor will test
count before incrementing it and if it is zero, will initialize the
statics for your class Foo. Since the value of count is now
incremented, any further encounters with this header code will not
cause re-initialization of Foo's statics.  The destructor can do any
clean up that might be necessary.  

It is important to note that the point in the Foo_Starter constructor
where it initializes the static is NOT where the static is defined.
The static MUST still be defined in some file that will occur once and
ONLY once in a program; that is to say in a .c file.  So, if this
header file is called Foo.h and Foo's member functions are defined in
a file called Foo.c, you will need to define the statics at file-scope
level in Foo.c.

Please note that this "fix" prevents you from declaring either an
extern or static to be a const or a *const since the initialization
will not be able to take place at the same point as definition.

All of this folderol is necessary because C++ does not specify any
order to the initialization of objects with external linkage. 
Some hack (er.. trick,   er.... technique) like this is absolutely
essential if you are going to declare any instances of Foo at
file-scope level and if the construction of those instances relies
on the existance of some meaningfull data existing in the statics.

Refer to section 3.4 of the ARM for a more detailed
explaination/excuse of this stuff.

It is to be hoped that X3J16 will take some positive action with
regard to the order of initialization of object with external linkage
so that hacks like this will not be needed in the future.


-- 
"Exploring the consensual hallucination of cyberspace"
Walter L. Peterson, Jr.
Internet   : wlp@calmasd.Prime.COM        CompuServe : 70441,3177                   
"The opinions expressed here are my own." 

jeffw@sparc27.tamu.EDU (Jeffrey A Waller) (03/08/91)

In article <2390@calmasd.Prime.COM>, wlp@calmasd.Prime.COM (Walter L. Peterson, Jr.) writes:
|> In article <1991Mar4.224519.6434@bronze.ucs.indiana.edu> nsundare@copper.ucs.indiana.edu (Neelakantan Sundaresan) writes:
|> >
|> >I am trying to solve the problem of initializing the static(shared) data
|> >area of a class type. Basically I would like this initializtion and any
|> >other house keeping stuff done, when the first object instance of that
|> >class is 'construct'ed. Is there a neat way to achieve this?
|> >
|> 
|> There is no "neat" way to do this. There is, however, "A" way to do
|> this. What you need to do is create yet another class.


I would only agree if this data area included static class members which required 
dynamic initialization.  Otherwise leave everything in the class:

class Foo
{  private:

      static int count;

      .
      .
      .

      void initialize_static_stuff();

   public:

       Foo()
       {  if(!count++) initialize_static_stuff();

          .
          .
          .

       }
};


Obviously, there are restrictions, though it works with what I find to be the
most common sort of initialization -- calling malloc and/or new. 

							-Jeff 

wlp@calmasd.Prime.COM (Walter L. Peterson, Jr.) (03/13/91)

In article  <13174@helios.TAMU.EDU|> jeffw@sparc27.tamu.EDU (Jeffrey A Waller) writes:
|>I would only agree if this data area included static class members which required 
|>dynamic initialization.  Otherwise leave everything in the class:
|>
|>class Foo
|>{  private:
|>
|>      static int count;
|>      .
|>      .
|>      .
|>      void initialize_static_stuff();
|>
|>   public:
|>
|>       Foo()
|>       {  if(!count++) initialize_static_stuff();
|>          .
|>          .
|>          .
|>       }
|>};
|>
|>Obviously, there are restrictions, though it works with what I find to be the
|>most common sort of initialization -- calling malloc and/or new. 
|>



It is true that static data members that do not require dynamic initialization
do not need the technique from the ARM, however, they do not need this also 
dont, in general,  need this technique either.  They frequently can just be
initialized where they are declared in the class.

In any case there is one problem with the implementation shown above. That is
a problem with efficiency.  In the example above, the test of count will be
made every time an instance of Foo is created, even though it is only needed 
when the first instance is created. 

The example in my article, ( which was shamelessly cribbed from the ARM ) will
be executed exactly once upon the comming into scope of each translation unit
which included the header file.

If Foo is a class that might have many instances created, such as a 2D or 3D
point class in a CAD system, this efficiency issue can be significant.

Also, it is always possible to find specific solutions to specific problems
that are "better" for that particular problem than more general solutions.
The solution from the ARM which I wrote about is a very general solution, that
will work in virutally all cases.

Finally:  The exact technique used to hack arround this problem in C++ is not
and should not be the real issue. The real issue is that the current lack of 
definition of the order of initialization of externally linked objects is 
not an acceptable state of afairs and a proper solution to this problem must
be addressed by X3J16.




-- 
"Exploring the consensual hallucination of cyberspace"
 Walter L. Peterson, Jr.
 Internet   : wlp@calmasd.Prime.COM        CompuServe : 70441,3177
"The opinions expressed here are my own."