Topic: Static data member of class template not instantiated


Author: Jerry Leichter <leichter@smarts.com>
Date: 1997/12/15
Raw View
| The old trick of using an initializer on a global variable to run some
| code before main() was never a good idea, anyway.  When the definition
| of the global is in a library, the standard says nothing about whether
| the global is "in" the program or not.  And bundling external
| declarations into all-or-none translantion units is an increasingly
| obsolete way to structure code.  So this hack (using an initialized
| but unreferenced global variable - or static data member - to get some
| code to run before main) should be avoided.

I don't really disagree with the *philosophy*, but have to reject this
as practical advice.  What's the alternative?  Check a flag at every
entry point and initialize a module if needed?  This may be acceptable
for compiler-generated code - the "inefficiency" is grossly overstated
for virtually all applications - but completely unworkable if you have
to insert the tests by hand:  In any reasonably-sized system, you'll
leave one out.  Or the next guy to modify your code will forget to put
one in (even if *your* memory and ability to keep track of all the
little details is perfect :-) ).  And, of course, you'll never know
until the day comes when *that* entry point happens to be the first one
called, so the module won't be initialized.

Other languages have "top level code" in their modules, which is defined
to run before any entry point in the module is called.  For better or
worse, construtors for static or global objects are C++'s way of
expressing this kind of thing.  Yes, it can be a rather opaque way to
accomplish something "obvious"; yes, it can lead to unexpected
interactions with linkers and other OS components.  But disliking it
won't make it go away, since there really are no alternatives.

(Now, if I ever see a system that *documents* how this works in
combination with its threading support, I'll ... I don't even know
*what* to say about what I'll do....  Instead, we all get to guess,
experiment, hope that the implementors "did something reasonable" ...)

       -- Jerry
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/12/17
Raw View
Jerry Leichter <leichter@smarts.com> wrote in article
<349561CD.107D@smarts.com>...
> | The old trick of using an initializer on a global variable to run some
> | code before main() was never a good idea, anyway.
> | [Lots deleted]
>
> I don't really disagree with the *philosophy*, but have to reject this
> as practical advice.  What's the alternative?

In many cases replace:
  Foo x;
with
  Foo& X(){ static Foo x; return x; }
which ensures that x won't be used before its constructor is entered, and
that x won't be constructed if it isn't used.  In principle, an
implementation might use self-modifying code so that the "first time
called" test was implicit.  In practice, many operating systems like to
share object images, making self-modifying code expensive.

However, in environments where I can make the (non-portable) assumption
that globals are initialized before main, they provide an attractive
mechanism to register new classes in a factory, without modifying any
existing code.  I don't believe this can be done without globals.  There
are up and down sides to this.  I can add 'Star' shapes to my drawing
program without changing any existing code :-).  I can also link and ship
my program without including the 'Star' code and without getting link
errors :-(.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/12/22
Raw View
"Bill Wade" <bill.wade@stoner.com> writes:

|>  However, in environments where I can make the (non-portable) assumption
|>  that globals are initialized before main, they provide an attractive
|>  mechanism to register new classes in a factory, without modifying any
|>  existing code.  I don't believe this can be done without globals.  There
|>  are up and down sides to this.  I can add 'Star' shapes to my drawing
|>  program without changing any existing code :-).  I can also link and ship
|>  my program without including the 'Star' code and without getting link
|>  errors :-(.

And if your system supports DLL's, and the implementation executes
constructors when the DLL is loaded, you can even use this to add "Star"
code while the system is running.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: jamshid@xanadu.io.com (Jamshid Afshar)
Date: 1997/12/11
Raw View
I know that a class template's member functions are not instantiated
unless they are used, but aren't its static data memebers supposed to
always be instantiated?  Consider the appended code.  Shouldn't the
fact that a class derives from Base<T> cause a static data memer
Base<T>::r to be instantiated?  I found that with two different
compilers, g++ 2.7.2 and EDG 2.3.7, the object "r" was never
constructed (or destroyed).  Btw, VC++5sp3 fails to compile the code
due to a compiler bug.

Interestingly, I found that referencing "r" (eg, adding the statement
"Derived::r;" in main()) caused g++ to instantiate it, though EDG
needed a bit more work (I had to add a dummy data member and function
to Register and access it).

Jamshid Afshar
jamshid@io.com

----
   #include <stdio.h>

   class Register {
   public:
       Register( const char* class_name )
       { printf("In Register ctor for class %s.\n", class_name); }
       ~Register()
       { printf("In Register dtor.\n"); }
   };

   template<class T>
   class Base {
   public:
       static Register r;
   };

   template<class T>
   Register Base<T>::r( "Base<T>" );

   class Derived : public Base<Derived> {};

   int main() {
       return 0;
   }
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: jamshid@xanadu.io.com (Jamshid Afshar)
Date: 1997/12/13
Raw View
I know that a class template's member functions are not instantiated
unless they are used, but aren't its static data memebers supposed to
always be instantiated?  Consider the appended code.  Shouldn't the
fact that a class derives from Base<T> cause a static data memer
Base<T>::r to be instantiated?  I found that with two different
compilers, g++ 2.7.2 and EDG 2.3.7, the object "r" was never
constructed (or destroyed).  Btw, VC++5sp3 fails to compile the code
due to a compiler bug.

Interestingly, I found that referencing "r" (eg, adding the statement
"Derived::r;" in main()) caused g++ to instantiate it, though EDG
needed a bit more work (I had to add a dummy data member and function
to Register and access it).

Jamshid Afshar
jamshid@io.com

----
   #include <stdio.h>

   class Register {
   public:
       Register( const char* class_name )
       { printf("In Register ctor for class %s.\n", class_name); }
       ~Register()
       { printf("In Register dtor.\n"); }
   };

   template<class T>
   class Base {
   public:
       static Register r;
   };

   template<class T>
   Register Base<T>::r( "Base<T>" );

   class Derived : public Base<Derived> {};

   int main() {
       return 0;
   }
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: bill@gibbons.org (Bill Gibbons)
Date: 1997/12/13
Raw View
In article <66pme2$24c$1@nntp-3.io.com>, jamshid@xanadu.io.com (Jamshid
Afshar) wrote:

> I know that a class template's member functions are not instantiated
> unless they are used, but aren't its static data memebers supposed to
> always be instantiated?

No.  Class templates may be instantiated in some very surprising places.
In some cases a class template may be instantiated even though there is no
possibility that the resulting type will ever be used by the program,
and there are cases where it is implementation-dependent whether such
an instantiation occurs.

So it is important that instantiating a class template does not have
side-effects, particularly at runtime.  Executing the initializer for
a static data member would be one such side-effect, if instantiating
the class implicitly instantiated the static data member.


The old trick of using an initializer on a global variable to run some
code before main() was never a good idea, anyway.  When the definition
of the global is in a library, the standard says nothing about whether
the global is "in" the program or not.  And bundling external declarations
into all-or-none translantion units is an increasingly obsolete way to
structure code.  So this hack (using an initialized but unreferenced
global variable - or static data member - to get some code to run before
main) should be avoided.


-- Bill Gibbons
   bill@gibbons.org
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]