Re: Functional Local Static Zero Initialization - When?
On Dec 5, 2:22 am, James Kanze <james.ka...@gmail.com> wrote:
On Dec 5, 3:38 am, Brian Cole <col...@gmail.com> wrote:
A working draft of the C++ standard I was able to obtain says
the following in section 6.7.4:
The zero-initialization (8.5) of all local objects with static
storage duration (3.7.1) or thread storage duration (3.7.2) is
performed before any other initialization takes place.
First, the only addition for C++0x is the thread storage
duration, so I assume the sentence was the following for
previous versions of the standard:
The zero-initialization (8.5) of all local objects with static
storage duration (3.7.1) is performed before any other
initialization takes place.
The criteria "before any other initialization" is a little
ambiguous here. Does this mean any other initialization inside
the function the static resides, or any other initialization
the entire program may perform.
I don't see any ambiguity. "Before any other initialization"
means "before any other initialization".
I guess the ambiguity is in my own mind fueled by the rest of the
paragraph:
"A local object of trivial or literal type (3.9) with static or thread
storage duration initialized with constant-expressions is initialized
before its
block is =EF=AC=81rst entered."
Hinting that the zero-initialization could occur after main is invoked
as long as it's before the function is entered. The next sentence only
says the implementation is "permitted" to perform initialization
before main, doesn't seem to require it:
"An implementation is permitted to perform early initialization of
other local objects with static or thread storage duration under the
same conditions that an implementation is permitted to statically
initialize an object with static or thread storage duration in
namespace scope (3.6.2)."
I am willing to accept that any decent compiler implementation would
zero out all the memory defined for function local statics during
"zero-initialization" since that would be cheaper than doing it during
main. Just wanted to be sure. Any idea what standard this guarantee
first appeared in? I deal with some rather old compilers sometimes.
Of course, if the compiler can determine that a conformant
program cannot see the difference... I rather suspect that no
implementation actually initializes the thread local storage
before the thread using it is created.
Basically, I'm trying to implement something like the
following to allow for thread safe function local static
initialization while maintaining proper destructor ordering
atexit.
template<class T>
struct Once
{
T *_obj;
long _once;
Once()
{
while (1)
{
long prev = InterlockedCompareExchange(&_once, 1=
, 0);
if (0 == prev) // got the lock
break;
else if (2 == prev) // The singleton has been =
initialized.
return _obj;
else {
// Another thread is initializing the singl=
eton: must wait.
assert(1 == prev);
sleep(1); // sleep 1 millisecond
That's one second, not one millisecond. At least on Posix
platforms, and I'm pretty sure Windows as well. (There is no
C++ standard function sleep.)
}
}
assert(_obj == 0);
_obj = new T;
InterlockedExchange(&_once, 2);
return _obj;
}
~Once() { delete _obj; }
inline T& operator *() { return *_obj; }
inline T* operator ->() { return _obj; }
inline operator T* () { return operator ->(); }
};
If I can guarantee that the memory of the object is
zero-initialized during "static initialization",
It will be if the object has static storage duration. Otherwise
not.
So the next obvious question is if there is a way I can force users of
the class to always declare it "static" since the implementation will
depend on this condition. Since static is a storage class specifier
and has nothing to do with the type there is no fancy typedef trickery
I could do to catch the following misuse of the class:
Foo *GetMeyersSingletonFoo()
{
Once<Foo> foo;
return foo;
}
The only hope is that during testing that foo would get placed in some
memory on the stack that wasn't already zero'd out, triggering an
assertion in the constructor. Seeing that memory is often zero'd out
for various reasons it seems way to easy for this to fall through
testing and only appear in production down the road.
Can any C++ wizards think of a way to catch this at compile or run
time?
Thanks