I have a function that can be reduced to this:
void f() {
static MyObject o("hello");
DoSomethingWith(o);
}
This function is called across a C API boundary, so like a good boy, I use try
to catch any exceptions that are thrown before they cross the boundary and screw things up:
void f() {
try {
static MyObject o("hello");
DoSomethingWith(o);
} catch (const MyObjectException& e) {
Message("Constructor of o failed");
}
}
This function is called the first time and I get the message "Constructor of o failed"
. However, later, the function is called again, and I get the message again. I get the message as many times as f
is called. I am using Visual C++ so this tells me what MSVC++ does, but not what should be done.
My question is, what should happen when the constructor of a static
function variable terminates unusually (by throw
ing, a longjmp
out of the constructor, termination of the thread that it's in, etc)? Also what should happen with any other static
variables declared before and after it? I would appreciate any relevant quotes from the standard as well.
Variables can also be declared static inside a function. This feature means the variable is not automatic, i.e. allocated and freed on the stack with each invocation of the function. Instead the variable is allocated in the static data area, it is initialized to zero and persists for the life of the program.
Static − A variable is created when the declaration is executed for the first time. It is destroyed when the execution stops/terminates. Dynamic − The variables memory is allocated and deallocated through memory management functions.
The space for the static variable is allocated only one time and this is used for the entirety of the program. Once this variable is declared, it exists till the program executes. So, the lifetime of a static variable is the lifetime of the program.
static. The static keyword can be used to declare variables and functions at global scope, namespace scope, and class scope. Static variables can also be declared at local scope. Static duration means that the object or variable is allocated when the program starts and is deallocated when the program ends.
Section 6.7 ([stmt.dcl]
) of the C++11 standard states that
The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.
Q: what should happen when the constructor of a static function variable terminates unusually [...] ?
A:
§6.7 [stmt.dcl] p4
[...] Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
So the initialization of o
will be tried again if it exits by throwing an exception. I think the same applies to any kind of abnormal exit from the initialization, though it's not explicitly stated. Brb, looking for more quotes.
Since I couldn't find anything related, I opened a follow-up question.
Q: Also what should happen with any other static variables declared before and after it?
A: Nothing, as long as neither the thread or the whole program terminate.
§3.6.3 [basic.start.term]
Destructors (12.4) for initialized objects (that is, objects whose lifetime (3.8) has begun) with static storage duration are called as a result of returning from
main
and as a result of callingstd::exit
(18.5). Destructors for initialized objects with thread storage duration within a given thread are called as a result of returning from the initial function of that thread and as a result of that thread callingstd::exit
. The completions of the destructors for all initialized objects with thread storage duration within that thread are sequenced before the initiation of the destructors of any object with static storage duration.
§3.7.2 [basic.stc.thread]
A variable with thread storage duration shall be initialized before its first odr-use (3.2) and, if constructed, shall be destroyed on thread exit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With