Topic: initialization of nonlocal static objects
Author: "Wil Evers" <wil@ittpub.nl>
Date: 1996/03/28 Raw View
In article <KANZE.96Mar27134634@gabi.gabi-soft.fr> kanze@gabi-soft.fr (J.
Kanze) writes:
> class X
> {
> public :
> enum DontInit { dontInit } ;
> X( DontInit ) {}
> X() : i( 5 ) {}
> private :
> int i ;
> } ;
>
> Objects to be initialized by the nifty_counter would be defined thus:
>
> X obj( X::dontInit ) ;
>
> Nifty counter then becomes:
>
> class NiftyCounter
> {
> static int cnt ;
> public :
> NiftyCounter()
> {
> if ( cnt == 0 )
> new( &obj ) X ;
> cnt ++ ;
> }
> } ;
>
> (Note that for NiftyCounter to work, it is absolutely essential that the
> definition of the object invoke a no-op constructor, since the object
> may in fact already be constructed.)
>
> As you can see, this works equally well for const objects.
I don't think so. For this to work on a const object, you would at least have
to cast away its constness - after all, the standard placement new operator
takes a void * as its second argument, not a const void *.
In my opinion, the `dummy constructor' technique is fundamentally bad. It
requires that all base classes and member variables have dummy constructors
too, so it is not always applicable.
When I use the nifty counter idiom, I normally construct the global
object in a suitably aligned raw memory buffer (a character array).
Users access the constructed object through a properly typed global
reference pointing to the raw memory buffer.
- Wil
---
[ 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: kanze@gabi-soft.fr (J. Kanze)
Date: 1996/03/29 Raw View
In article <009A0041E919D6E0.3D60EEDA@ittpub.nl> "Wil Evers"
<wil@ittpub.nl> writes:
|> In article <KANZE.96Mar27134634@gabi.gabi-soft.fr> kanze@gabi-soft.fr (J.
|> Kanze) writes:
|> > class X
|> > {
|> > public :
|> > enum DontInit { dontInit } ;
|> > X( DontInit ) {}
|> > X() : i( 5 ) {}
|> > private :
|> > int i ;
|> > } ;
|> >
|> > Objects to be initialized by the nifty_counter would be defined thus:
|> >
|> > X obj( X::dontInit ) ;
|> >
|> > Nifty counter then becomes:
|> >
|> > class NiftyCounter
|> > {
|> > static int cnt ;
|> > public :
|> > NiftyCounter()
|> > {
|> > if ( cnt == 0 )
|> > new( &obj ) X ;
|> > cnt ++ ;
|> > }
|> > } ;
|> >
|> > (Note that for NiftyCounter to work, it is absolutely essential that the
|> > definition of the object invoke a no-op constructor, since the object
|> > may in fact already be constructed.)
|> >
|> > As you can see, this works equally well for const objects.
|> I don't think so. For this to work on a const object, you would at least have
|> to cast away its constness - after all, the standard placement new operator
|> takes a void * as its second argument, not a const void *.
You're right. I'm getting careless. (And the last time I did this, my
compiler still didn't enforce const-ness in this case.)
|> In my opinion, the `dummy constructor' technique is fundamentally bad. It
|> requires that all base classes and member variables have dummy constructors
|> too, so it is not always applicable.
|> When I use the nifty counter idiom, I normally construct the global
|> object in a suitably aligned raw memory buffer (a character array).
|> Users access the constructed object through a properly typed global
|> reference pointing to the raw memory buffer.
IMHO, the nifty counter idiom is in general not very good. I much
prefer to avoid the global or class static, and require the user to call
a function which returns a reference to a local static.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller 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: jgealow@mtl.mit.edu (Jeffrey C. Gealow)
Date: 1996/03/24 Raw View
I've encountered trouble with the initialization of nonlocal static
objects. The following parts of the ARM are relevant:
ARM 3.4
The initialization of nonlocal static objects in a translation unit is
done before the first use of any function or object defined in that
translation unit. Such initializations may be done before the first
statement of main() or deferred to any point in time before the first
use of a function or object defined in that translation unit. The
default initialization of all static objects to zero is performed
before any dynamic (that is, run-time) initialization. No further
order is imposed on the initialization of objects from different
translation units.
ARM 3.4 annotation
A useful technique for insuring that a global object is initialized
only once and before its first use is to maintain a count of the
number of translation units using it.
ARM 7.1.6
A const object may be initialized, but its value may not be changed
thereafter.
Are the following observations correct?
The technique described in the ARM 3.4 annotation cannot be applied to
const objects since the values of the objects may not be changed.
The ARM 3.4 guarantee that the "initialization of nonlocal static
objects in a translation unit is done before the first use of any
function or object defined in that translation unit" is not accurate.
Functions or objects defined in a translation unit may be used in the
initialization of nonlocal static objects defined in other translation
units. Therefore, mutual dependencies may make it impossible to honor
the guarantee.
The C++ standard could be revised to include a guarantee that whenever
possible, the initialization of nonlocal static objects in a translation
unit is done before any function or object in that translation unit is
used to initialize objects in other translation units. Otherwise,
const objects should not be used.
The Sun SPARCompiler C++ 4.1 and G++ 2.7.2 don't even honor the ARM
guarantee when there are no mutual dependencies. The following
example illustrates the problem. There are four files: library.cc,
library.h, luser.cc, and main.cc. The behavior of the program depends
on the order in which files are specified in the compile command:
gator jgealow % $CC main.cc luser.cc library.cc
gator jgealow % ./a.out
global: 0
local: 6
gator jgealow % $CC main.cc library.cc luser.cc
gator jgealow % ./a.out
global: 6
local: 6
Jeff
::::::::::::::
library.h
::::::::::::::
class X {
public:
int i;
X(int);
};
class Y {
public:
int i;
Y();
};
::::::::::::::
library.cc
::::::::::::::
#include "library.h"
const X Int_(0);
const X Int0(1);
const X Int1(2);
const X Intx(3);
X :: X( int x) : i(x)
{}
Y :: Y( )
{
i = Int_.i + Int0.i + Int1.i + Intx.i;
}
::::::::::::::
luser.cc
::::::::::::::
#include "library.h"
Y global;
::::::::::::::
main.cc
::::::::::::::
#include <iostream.h>
#include "library.h"
extern Y global;
int main(int, char* argv[])
{
Y local;
cout << "global: " << global.i << endl;
cout << "local: " << local.i << endl;
}
---
[ 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: James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de>
Date: 1996/03/25 Raw View
In article <4j1tm6$bmu@senator-bedfellow.MIT.EDU> jgealow@mtl.mit.edu
(Jeffrey C. Gealow) writes:
|> I've encountered trouble with the initialization of nonlocal static
|> objects. The following parts of the ARM are relevant:
|> ARM 3.4
|> The initialization of nonlocal static objects in a translation unit is
|> done before the first use of any function or object defined in that
|> translation unit. Such initializations may be done before the first
|> statement of main() or deferred to any point in time before the first
|> use of a function or object defined in that translation unit. The
|> default initialization of all static objects to zero is performed
|> before any dynamic (that is, run-time) initialization. No further
|> order is imposed on the initialization of objects from different
|> translation units.
|> ARM 3.4 annotation
|> A useful technique for insuring that a global object is initialized
|> only once and before its first use is to maintain a count of the
|> number of translation units using it.
|> ARM 7.1.6
|> A const object may be initialized, but its value may not be changed
|> thereafter.
|> Are the following observations correct?
|> The technique described in the ARM 3.4 annotation cannot be applied to
|> const objects since the values of the objects may not be changed.
No. Const has nothing to do with the question, since objects only
become const after construction.
|> The ARM 3.4 guarantee that the "initialization of nonlocal static
|> objects in a translation unit is done before the first use of any
|> function or object defined in that translation unit" is not accurate.
|> Functions or objects defined in a translation unit may be used in the
|> initialization of nonlocal static objects defined in other translation
|> units. Therefore, mutual dependencies may make it impossible to honor
|> the guarantee.
Correct.
|> The C++ standard could be revised to include a guarantee that whenever
|> possible, the initialization of nonlocal static objects in a translation
|> unit is done before any function or object in that translation unit is
|> used to initialize objects in other translation units. Otherwise,
|> const objects should not be used.
Somehow, I don't think that these exact words can be used.
I believe that the intent of the current draft is that rule in ARM 3.4
hold only for uses invoked directly or indirectly from main, but not
for uses which result from the construction of other static objects.
|> The Sun SPARCompiler C++ 4.1 and G++ 2.7.2 don't even honor the ARM
|> guarantee when there are no mutual dependencies.
And nor do any other compilers I'm aware of. In practice, it is best
to assume that there are no guarantees whatsoever between compilation
units. (On the other hand, it is generally safe to assume that all
initialization will take place before main, at least if you are not
using DLL's. This is not guaranteed by the draft, however.)
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, tudes et r alisations en logiciel orient objet --
-- A la recherche d'une activit dans une region francophone
[ 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: jgealow@mtl.mit.edu (Jeffrey C. Gealow)
Date: 1996/03/26 Raw View
In article <9603251201.AA24987@lts.sel.alcatel.de> James Kanze
US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> writes:
In article <4j1tm6$bmu@senator-bedfellow.MIT.EDU> jgealow@mtl.mit.edu
(Jeffrey C. Gealow) writes:
|> The technique described in the ARM 3.4 annotation cannot be applied to
|> const objects since the values of the objects may not be changed.
No. Const has nothing to do with the question, since objects only
become const after construction.
I don't understand James Kanze's comment. Consider:
// file nifty_library.h:
//
class X {
public:
int i;
X() : i(10) {};
};
extern const X obj;
class nifty_counter {
static nifty_count;
public:
nifty_counter() {
if (nifty_count++ == 0) {
obj.i = 5;
}
}
};
// file nifty_library.cc:
//
#include "nifty_library.h"
const X obj;
The intent of the statement obj.i = 5 in nifty_counter::nifty_counter()
is to "initialize" obj. But formally, obj is initialized by the
default constructor for class X.
% CC -c nifty_library.cc
"nifty_library.h", line 17: Error: The left operand cannot be assigned to.
1 Error(s) detected.
% CC -Dconst="" -c nifty_library.cc
Perhaps the problem may be circumvented by casting away const: ((X) obj).i = 5;
I believe that the intent of the current draft is that rule in ARM 3.4
hold only for uses invoked directly or indirectly from main, but not
for uses which result from the construction of other static objects.
Perhaps the intent should be clarified in the text of the draft.
Jeff
[ 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: kanze@gabi-soft.fr (J. Kanze)
Date: 1996/03/27 Raw View
In article <ky3f6w679u.fsf@gator.mit.edu> jgealow@mtl.mit.edu (Jeffrey
C. Gealow) writes:
|> In article <9603251201.AA24987@lts.sel.alcatel.de> James Kanze
|> US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> writes:
|> In article <4j1tm6$bmu@senator-bedfellow.MIT.EDU> jgealow@mtl.mit.edu
|> (Jeffrey C. Gealow) writes:
|> |> The technique described in the ARM 3.4 annotation cannot be applied
|> |> to const objects since the values of the objects may not be changed.
|> No. Const has nothing to do with the question, since objects only
|> become const after construction.
|> I don't understand James Kanze's comment. Consider:
|> // file nifty_library.h:
|> //
|> class X {
|> public:
|> int i;
|> X() : i(10) {};
|> };
|> extern const X obj;
|> class nifty_counter {
|> static nifty_count;
|> public:
|> nifty_counter() {
|> if (nifty_count++ == 0) {
|> obj.i = 5;
|> }
|> }
|> };
|> // file nifty_library.cc:
|> //
|> #include "nifty_library.h"
|> const X obj;
|> The intent of the statement obj.i = 5 in nifty_counter::nifty_counter()
|> is to "initialize" obj. But formally, obj is initialized by the
|> default constructor for class X.
But normally, you wouldn't try and do it this way, anyway. It is rare
that initialization is so simple, and even rarer that it only involves
public members.
The usual solution would be to provide two constructors for X, a dummy
which does nothing, and the real one used by the nifty_counter. Thus:
class X
{
public :
enum DontInit { dontInit } ;
X( DontInit ) {}
X() : i( 5 ) {}
private :
int i ;
} ;
Objects to be initialized by the nifty_counter would be defined thus:
X obj( X::dontInit ) ;
Nifty counter then becomes:
class NiftyCounter
{
static int cnt ;
public :
NiftyCounter()
{
if ( cnt == 0 )
new( &obj ) X ;
cnt ++ ;
}
} ;
(Note that for NiftyCounter to work, it is absolutely essential that the
definition of the object invoke a no-op constructor, since the object
may in fact already be constructed.)
As you can see, this works equally well for const objects.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
---
[ 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 ]