Topic: Q: Initialization order of static objects
Author: "Alexey N. Solofnenko" <trelony@usa.net>
Date: 1997/07/09 Raw View
This is a cryptographically signed message in MIME format.
--------------ms692C978D31DE8F251EB3541C
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 7bit
Another way is to provide function or static method which contains
static variable. The variable will be initialized during first function
call. But I am not sure if it is thread safe.
class X {
protected:
X();
~X();
public:
static X& instance() {
static X x;
return x;
}
};
Bob Steagall wrote:
> Karsten Theis <theis@irf.de> wrote:
>
> >How can I effect the order of initialization of static objects?
>
> >The following code causes MSVC 4.2 to call the function
> 'sm_C1.Func1()'
> >before the static member 'sm_C1' of class C2 is initialized and its
> >constructor is called:
>
> [...snip...]
>
> >The problem is, that sm_C2 and sm_C1 are from different files, and
> >therefore I don't know the initialization order.
> >In my actual problem sm_C1 is defined in a static linked library and
> >'sm_C2' is defined in a DLL using the library.
>
> There is no language-supported means of affecting the order of
> initialization of non-simple, non-local static objexts. (As an aside,
>
> Carroll and Ellis have an excellent discussion of this problem in
> their
> book "Designing and Coding Reusable C++".)
>
> One possible solution is to use an automatic initializer object:
>
> //- File utils.h
> //
> template <class T>
> class auto_initializer
> {
> T* ptr;
> char rawdata[sizeof(T)];
>
> public:
> T* operator->()
> {
> if (ptr == 0)
> {
> ptr = new (rawdata) T;
> }
> return ptr;
> }
> };
>
> //- File 1.h
> //
> class C1
> {
> public:
> C1( );
> ~C1( );
> Func1( );
> };
>
> //- File 2.h
> //
> class C2
> {
> public:
> C2( );
> ~C2( );
> static auto_initializer<C1> sm_C1;
> }
>
> //- File 2.cpp
> //
> auto_initializer<C1> C2::sm_C1;
>
> C2::C2()
> {
> sm_C1->Func1();
> }
>
> //- File 3.cpp
> //
> static C2 sm_C2();
>
> Of course, there are issues with regard to cleanup of resources, etc,
> from the C1 instance you have manually constructed. Since the call to
>
> operator->() is inline, you only have the cost of an additional
> comparison in C2::C2() for all C2 instances except the first one.
>
> XTL uses a similar technique for ensuring the correct initialization
> of
> a string engine examplar for its string classes, with great success.
>
> --Bob
>
> ====================================================================
> Bob Steagall steagall@deltalogic.com
> DeltaLogic, Inc. http://www.deltalogic.com
> 1537 Kew Road Voice (216) 321-8200
> Cleveland Hts, OH 44118-1204 Fax (216) 321-6976
> ---
> [ 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
> ]
--
Alexey Solofnenko,
Typhoon Software,
mailto:trelony@usa.net
--------------ms692C978D31DE8F251EB3541C
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature
<encoded_portion_removed>
+SK5+lE=
--------------ms692C978D31DE8F251EB3541C--
---
[ 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: steagall@deltalogic.com (Bob Steagall)
Date: 1997/07/04 Raw View
Karsten Theis <theis@irf.de> wrote:
>How can I effect the order of initialization of static objects?
>The following code causes MSVC 4.2 to call the function 'sm_C1.Func1()'
>before the static member 'sm_C1' of class C2 is initialized and its
>constructor is called:
[...snip...]
>The problem is, that sm_C2 and sm_C1 are from different files, and
>therefore I don't know the initialization order.
>In my actual problem sm_C1 is defined in a static linked library and
>'sm_C2' is defined in a DLL using the library.
There is no language-supported means of affecting the order of
initialization of non-simple, non-local static objexts. (As an aside,
Carroll and Ellis have an excellent discussion of this problem in their
book "Designing and Coding Reusable C++".)
One possible solution is to use an automatic initializer object:
//- File utils.h
//
template <class T>
class auto_initializer
{
T* ptr;
char rawdata[sizeof(T)];
public:
T* operator->()
{
if (ptr == 0)
{
ptr = new (rawdata) T;
}
return ptr;
}
};
//- File 1.h
//
class C1
{
public:
C1( );
~C1( );
Func1( );
};
//- File 2.h
//
class C2
{
public:
C2( );
~C2( );
static auto_initializer<C1> sm_C1;
}
//- File 2.cpp
//
auto_initializer<C1> C2::sm_C1;
C2::C2()
{
sm_C1->Func1();
}
//- File 3.cpp
//
static C2 sm_C2();
Of course, there are issues with regard to cleanup of resources, etc,
from the C1 instance you have manually constructed. Since the call to
operator->() is inline, you only have the cost of an additional
comparison in C2::C2() for all C2 instances except the first one.
XTL uses a similar technique for ensuring the correct initialization of
a string engine examplar for its string classes, with great success.
--Bob
====================================================================
Bob Steagall steagall@deltalogic.com
DeltaLogic, Inc. http://www.deltalogic.com
1537 Kew Road Voice (216) 321-8200
Cleveland Hts, OH 44118-1204 Fax (216) 321-6976
---
[ 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: jim.hyslop@leitch.com (Jim Hyslop)
Date: 1997/07/08 Raw View
In article <01bc87c8$039a15d0$9bc8d981@kathei> on 03 Jul 1997 09:14:52
PDT, theis@irf.de says...
> How can I effect the order of initialization of static objects?
[snip]
> The problem is, that sm_C2 and sm_C1 are from different files, and
> therefore I don't know the initialization order.
> In my actual problem sm_C1 is defined in a static linked library and
> 'sm_C2' is defined in a DLL using the library.
Instead of embedding an instance of C1 inside C2, make it a pointer to
C1. Make C2 an instance-counting class. In C2's ctor, check to see
if the static pointer has been assigned; if not, create a new C1. In
C2's dtor, check to see if this is the last instance of C2 to be
destroyed, if so delete the static pointer and set it to NULL.
// file2.h
class C1;
class C2
{
private:
static C1 *sm_C1;
public:
C2();
~C2();
}
// file2.cpp
C1 *C2::sm_C1=0;
static int instanceCount_=0;
C2::C2()
{
// Note that this must be replicated in copy ctor & overloaded
// ctors as well - you may want to put this in a separate member
// function init() that is called by all ctors.
if(instanceCount_++ == 0)
{
assert(sm_C1==NULL);
sm_C1 = new C1;
}
// remainder if initialization
}
C2::~C2()
{
if (--instanceCount_ == 0)
{
assert(sm_C1);
delete sm_C1;
sm_C1=NULL;
}
// remainder of cleanup
}
Note that by changing sm_C1 to a pointer, you have also decreased
file3.cpp's dependencies - if you change C1 you will no longer have to
recompile file3.cpp
--
Jim Hyslop O-
Shamelessly purloined from someone else's sig:
He who lives in glass houses should not invite he who is without sin.
Don't pass on that email about someone dying of cancer or a "new
super-powerful computer virus" until you check out the Internet Hoax
page http://ciac.llnl.gov/ciac/CIACHoaxes.html first!
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: John Hancock <jhancock+@cs.cmu.edu>
Date: 1997/07/08 Raw View
In article <01bc87c8$039a15d0$9bc8d981@kathei>,
Karsten Theis <theis@irf.de> wrote:
>How can I effect the order of initialization of static objects?
>
>The following code causes MSVC 4.2 to call the function 'sm_C1.Func1()'
>before the static member 'sm_C1' of class C2 is initialized and its
>constructor is called:
>
>File 1.h:
>class C1 {
> C1( );
> ~C1( );
> Func1( );
>};
>
>File 2.h:
>class C2 {
> C2( );
> ~C2( );
> static C1 sm_C1;
>}
>
>File 2.cpp
>C1 C2::sm_C1( )
>C2::C2( )
>{
> sm_C1.Funk( );
>}
>
>File 3.cpp
>static C2 sm_C2( );
>
>The problem is, that sm_C2 and sm_C1 are from different files, and
>therefore I don't know the initialization order.
>In my actual problem sm_C1 is defined in a static linked library and
>'sm_C2' is defined in a DLL using the library.
>
>Normaly I try to avoid static members, but for this special problem it's
>the best solution.
I was bitten by this problem once before. There's a trick found in
Item 47 of Scott Meyer's "Effective C++" book to solve this. If you
haven't read the book, I highly recommend it. The 2nd book
"More Effective C++" is also excellent.
The main trick is to use a file static initializer class for whichever
class needs to be initialized first.
You put in File2.h:
class C2_init {
private:
static int count;
public:
C2_init();
~C2_init();
}
static C2_init c2_init;
Make a class C2_init with a static count and a constructor and destructor.
The count is used to keep track of the total number of C2_init objects
that exist. The C2_init constructor simply initializes
C2::sm_C1 if the count is zero and increments the count. C2_init
is usually a friend of C2. The C2_init destructor is made to clean
up stuff in C2, i.e. sm_C1 once the decremented count is zero.
When File3 tries to access C2, it will have included the file static
C2_init which will now have initialized sm_C1.
Go see the book for more details.
Hope this help,
John
--
--------------------------------------------------------------------------
John A. Hancock, Robotics Institute, Carnegie Mellon University
jhancock@ri.cmu.edu, http://www.ius.cs.cmu.edu/~jhancock/
"He who laughs has not yet heard the bad news." -- Bertolt Brecht
---
[ 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: steagall@deltalogic.com (Bob Steagall)
Date: 1997/07/09 Raw View
John Hancock <jhancock+@cs.cmu.edu> wrote:
>I was bitten by this problem once before. There's a trick found in
>Item 47 of Scott Meyer's "Effective C++" book to solve this. If you
>haven't read the book, I highly recommend it. The 2nd book
>"More Effective C++" is also excellent.
>The main trick is to use a file static initializer class for whichever
>class needs to be initialized first.
>You put in File2.h:
>class C2_init {
>private:
> static int count;
>public:
> C2_init();
> ~C2_init();
>}
>static C2_init c2_init;
>Make a class C2_init with a static count and a constructor and destructor.
>The count is used to keep track of the total number of C2_init objects
>that exist. The C2_init constructor simply initializes
>C2::sm_C1 if the count is zero and increments the count. C2_init
>is usually a friend of C2. The C2_init destructor is made to clean
>up stuff in C2, i.e. sm_C1 once the decremented count is zero.
>When File3 tries to access C2, it will have included the file static
>C2_init which will now have initialized sm_C1.
>Go see the book for more details.
Using init objects as you have described will certainly work. However,
there are several disadvantages to using them, as pointed out by Carroll
and Ellis in Chapter 12 of "Designing and Coding Reusable C++":
1. The object code for C1 and C2 will be linked into any application
that uses the File2.h header, regardless of whether any C1 or C2
functionality is actually used.
2. Init objects can increase the run time of programs. Suppose File2.h
is included by many translation units in an application. Each of these
translation units will contain the definition of a C2_init init object
On a virtual memory system, calling the init object constructors will
cause all the pages containing init objects to be faulted at startup,
causing a noticeable delay. (Carroll and Ellis, pg 273)
3. (My observation) There are certain popular compilers that will not
create precompiled headers if static objects are defined in any header
file. This is not an error, per se, but on a big project with lots of
header files, it can be a real pain.
FWIW, when I was writing XTL I looked at several methods of static
initialization. It was an especially important issue with the string
class template, with which I wanted to use a static exemplar of the
string representation for constructing new string instances. After a
careful read of Carroll and Ellis (I can't recommend this book strongly
enough), I decided to use init checks. If you do them properly, they
only cost you a comparison operation. For all except the most trivial
constructors, this is a negligible cost.
--Bob
====================================================================
Bob Steagall steagall@deltalogic.com
DeltaLogic, Inc. http://www.deltalogic.com
1537 Kew Road Voice (216) 321-8200
Cleveland Hts, OH 44118-1204 Fax (216) 321-6976
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Karsten Theis <theis@irf.de>
Date: 1997/07/03 Raw View
How can I effect the order of initialization of static objects?
The following code causes MSVC 4.2 to call the function 'sm_C1.Func1()'
before the static member 'sm_C1' of class C2 is initialized and its
constructor is called:
File 1.h:
class C1 {
C1( );
~C1( );
Func1( );
};
File 2.h:
class C2 {
C2( );
~C2( );
static C1 sm_C1;
}
File 2.cpp
C1 C2::sm_C1( )
C2::C2( )
{
sm_C1.Funk( );
}
File 3.cpp
static C2 sm_C2( );
The problem is, that sm_C2 and sm_C1 are from different files, and
therefore I don't know the initialization order.
In my actual problem sm_C1 is defined in a static linked library and
'sm_C2' is defined in a DLL using the library.
Normaly I try to avoid static members, but for this special problem it's
the best solution.
If you've got an idea, please let me know...
Karsten Theis
email: theis@irf.de
---
[ 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
]