Re: dynamic initialization of local an non-local static variables
Am 03.01.2011 10:30, schrieb Gene Bushuyev:
A contrived example and questions below:
#include<iostream>
struct A
{
A(const char* msg) { std::cout<< msg<< std::endl; }
};
A non_local("non-local");
A& singleton()
{
static A local("local");
return local;
}
int main()
{
std::cout<< "main"<< std::endl;
singleton();
}
1) What are the possibilities here? Can "non-local", "local", and
"main" be printed in any order by conforming compiler?
No, there are some guaranteed constraints on the order, see below.
Do I understand
correctly that the standard allows dynamic initialization of non-local
variables with static storage duration to be deferred until the first
use, and also allows local variables with static storage duration to
be initialized early, before the first pass through the function?
According to 3.6.2 p. 4:
"If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized."
The function singleton() is defined in the same translation unit (TU) as the global variable non_local and thus local shall be initialized *after* non_local.
Two interesting questions remain:
a) Is there a guaranteed order between the initial output in main() and
the initialization of non_local?
b) How far can the allowance to perform dynamic initialization as static initialization be stretched in this example?
In regard to (a) it depends whether any of the functions or objects involved in the expression
std::cout<< "main" << std::endl
are defined in this TU or not. This expression involves
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
as well as ostream's member function
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
and a free operator overload for
ostream& operator<<(ostream&, const char*);
and all indirectly involved functions and objects.
Even though these are nominally function templates (except the middle one) an implementation is free to specialize these basic_ostream templates or members and to define them separately, since the template arguments don't involve user-defined types.
In regard to (b) it is important to realize that 3.6.2 p. 3 b. 1,
"the dynamic version of the initialization does not change the value of any other object of namespace scope prior to its initialization"
is a hard constraint for implementations. Specifically, the dynamic version of the local variable in singleton() *does* change the value of std::cout, therefore I don't see how it's initialization could be performed as a static initialization.
An open question for me is, whether implementations have to conserve an order of the initial output statement in main() and the initialization of non_local. Currently I cannot find wording that enforces one.
Finally note that the open issue
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#371
is slightly involved with this question.
2) Thread safety. The n3092 makes guarantees of thread safety of local
static variables in 6.7/4 "If control enters the declaration
concurrently while the variable is being initialized, the concurrent
execution shall wait for completion of the initialization." But I
can't find any affirmation that dynamic initialization of non-local
static variables is also thread safe. In fact, in multi-threaded
environment it's unclear what "initialization deferred until the first
use" means. The first use might not be always possible to determine.
There are no extra wording in regard to thread safety, so the existing rules implicitly apply. I think we need a specific example to discuss about.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]