If a variable is declared as static in a function's scope it is only initialized once and retains its value between function calls. What exactly is its lifetime? When do its constructor and destructor get called?
void foo()
{
static string plonk = "When will I die?";
}
The lifetime of function static variables begins the first time[0] the program flow encounters the declaration and it ends at program termination. This means that the run-time must perform some book keeping in order to destruct it only if it was actually constructed.
Additionally, since the standard says that the destructors of static objects must run in the reverse order of the completion of their construction[1], and the order of construction may depend on the specific program run, the order of construction must be taken into account.
Example
struct emitter {
string str;
emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
~emitter() { cout << "Destroyed " << str << endl; }
};
void foo(bool skip_first)
{
if (!skip_first)
static emitter a("in if");
static emitter b("in foo");
}
int main(int argc, char*[])
{
foo(argc != 2);
if (argc == 3)
foo(false);
}
Output:
C:>sample.exe
Created in foo
Destroyed in foo
C:>sample.exe 1
Created in if
Created in foo
Destroyed in foo
Destroyed in if
C:>sample.exe 1 2
Created in foo
Created in if
Destroyed in if
Destroyed in foo
[0] Since C++98[2] has no reference to multiple threads how this will be behave in a multi-threaded environment is unspecified, and can be problematic as Roddy mentions.
[1] C++98 section 3.6.3.1 [basic.start.term]
[2] In C++11 statics are initialized in a thread safe way, this is also known as Magic Statics.
Motti is right about the order, but there are some other things to consider:
Compilers typically use a hidden flag variable to indicate if the local statics have already been initialized, and this flag is checked on every entry to the function. Obviously this is a small performance hit, but what's more of a concern is that this flag is not guaranteed to be thread-safe.
If you have a local static as above, and foo is called from multiple threads, you may have race conditions causing plonk to be initialized incorrectly or even multiple times. Also, in this case plonk may get destructed by a different thread than the one which constructed it.
Despite what the standard says, I'd be very wary of the actual order of local static destruction, because it's possible that you may unwittingly rely on a static being still valid after it's been destructed, and this is really difficult to track down.
The existing explanations aren't really complete without the actual rule from the Standard, found in 6.7:
The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization 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. 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.
FWIW, Codegear C++Builder doesn't destruct in the expected order according to the standard.
C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if
... which is another reason not to rely on the destruction order!
The Static variables are come into play once the program execution starts and it remain available till the program execution ends.
The Static variables are created in the Data Segment of the Memory.
Related
If a variable is declared as static in a function's scope it is only initialized once and retains its value between function calls. What exactly is its lifetime? When do its constructor and destructor get called?
void foo()
{
static string plonk = "When will I die?";
}
The lifetime of function static variables begins the first time[0] the program flow encounters the declaration and it ends at program termination. This means that the run-time must perform some book keeping in order to destruct it only if it was actually constructed.
Additionally, since the standard says that the destructors of static objects must run in the reverse order of the completion of their construction[1], and the order of construction may depend on the specific program run, the order of construction must be taken into account.
Example
struct emitter {
string str;
emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
~emitter() { cout << "Destroyed " << str << endl; }
};
void foo(bool skip_first)
{
if (!skip_first)
static emitter a("in if");
static emitter b("in foo");
}
int main(int argc, char*[])
{
foo(argc != 2);
if (argc == 3)
foo(false);
}
Output:
C:>sample.exe
Created in foo
Destroyed in foo
C:>sample.exe 1
Created in if
Created in foo
Destroyed in foo
Destroyed in if
C:>sample.exe 1 2
Created in foo
Created in if
Destroyed in if
Destroyed in foo
[0] Since C++98[2] has no reference to multiple threads how this will be behave in a multi-threaded environment is unspecified, and can be problematic as Roddy mentions.
[1] C++98 section 3.6.3.1 [basic.start.term]
[2] In C++11 statics are initialized in a thread safe way, this is also known as Magic Statics.
Motti is right about the order, but there are some other things to consider:
Compilers typically use a hidden flag variable to indicate if the local statics have already been initialized, and this flag is checked on every entry to the function. Obviously this is a small performance hit, but what's more of a concern is that this flag is not guaranteed to be thread-safe.
If you have a local static as above, and foo is called from multiple threads, you may have race conditions causing plonk to be initialized incorrectly or even multiple times. Also, in this case plonk may get destructed by a different thread than the one which constructed it.
Despite what the standard says, I'd be very wary of the actual order of local static destruction, because it's possible that you may unwittingly rely on a static being still valid after it's been destructed, and this is really difficult to track down.
The existing explanations aren't really complete without the actual rule from the Standard, found in 6.7:
The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization 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. 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.
FWIW, Codegear C++Builder doesn't destruct in the expected order according to the standard.
C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if
... which is another reason not to rely on the destruction order!
The Static variables are come into play once the program execution starts and it remain available till the program execution ends.
The Static variables are created in the Data Segment of the Memory.
I can use C++11 or C++14 (or even C++17). Let's suppose I have a singleton object
class MyInstance {
public:
MyInstance() {
throw std::runtime_exception("something went wrong"); // Ctor might throw
}
};
MyInstance& getInstance() {
static MyInstance obj;
return obj;
}
Now, I made sure that every call to getInstance is wrapped in a
try {
auto& inst = getInstance();
} catch(std::runtime_error& e) {
// do something
}
What I'm wondering right now is: what happens if after failing an initialization in the constructor and throwing and catching and informing the user in the logs... the program passes again in a try codepath and calls getInstance again?
I made a few guesses but I have no idea if they're right:
The object has static storage so it will only be attempted to be built once I think?
Will returning a reference to an unconstructed object will get me a dangling reference and undefined behavior?
Would use a unique_ptr as static variable in place of obj solve this problem so I can access the pointer multiple times and also check if the object was properly constructed (if (uptr == TRUE)) ?
If the constructor throws the object is not initialized. So if control passes through getInstance again, initialization will be performed again as well.
[stmt.dcl] (emphasis mine)
4 Dynamic initialization of a block-scope variable with static
storage duration or thread storage duration is performed 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.
[stmt.dcl]/4: Dynamic initialization of a block-scope variable with static storage duration or thread storage duration is performed 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. [..]
No need to "guess"; you could put a std::cout trace inside MyInstance::MyInstance() and call getInstance() twice. 😊
Also no need for smart pointers; the object either exists or it doesn't, and there's no way to proceed inside getInstance() after the declaration without the object existing, because you threw an exception!
By the way, it's std::runtime_error, not std::runtime_exception.
Let's say I create:
class Hello {
public:
int World(int in)
{
static int var = 0; // <<<< This thing here.
if (in >= 0) {
var = in;
} else {
cout << var << endl;
}
}
};
Now, if I do:
Hello A;
Hello B;
A.World(10);
A.World(-1);
B.World(-1);
I'm getting output of "10" followed by another "10". The value of the local variable of a method just crossed over from one instance of a class to another.
It's not surprising - technically methods are just functions with a hidden this parameter, so a static local variable should behave just like in common functions. But is it guaranteed? Is it a behavior enforced by standard, or is it merely a happy byproduct of how the compiler handles methods? In other words - is this behavior safe to use? (...beyond the standard risk of baffling someone unaccustomed...)
Yes. It doesn't matter if the function is a [non-static] member of a class or not, it's guranteed to have only one instance of it's static variables.
Proper technical explanation for such variables is that those are objects with static duration and internal linkage - and thus those names live until program exits, and all instances of this name refer to the same entity.
Just one thing to add to the correct answer. If your class was templated, then the instance of var would only be shared amongst objects of the same instantiation type. So if you had:
template<typename C>
class Hello {
public:
int World(int in)
{
static int var = 0; // <<<< This thing here.
if (in >= 0) {
var = in;
} else {
cout << var << endl;
}
}
};
And then:
Hello<int> A;
Hello<int> B;
Hello<unsigned> C;
A.World(10);
A.World(-1);
B.World(-1);
C.World(-1);
Then the final output would be "0" rather than "10", because the Hello<unsigned> instantiation would have its own copy of var.
If we are talking about the Windows Compiler it's guaranteed
https://msdn.microsoft.com/en-us/library/y5f6w579.aspx
The following example shows a local variable declared static in a member function. The static variable is available to the whole program; all instances of the type share the same copy of the static variable.
They use an example very similar to yours.
I don't know about GCC
Yes, it is guaranteed. Now, to answer the question "Any risk of sharing local static variable of a method between instances?" it might be a bit less straightforward. There might be potential risks in the initialization and utilization of the variable and these risks are specific to variables local to the method (as opposed to class variables).
For the initialization, a relevant part in the standard is 6.7/4 [stmt.dcl]:
Dynamic initialization of a block-scope variable with static storage
duration (3.7.1) or thread storage duration (3.7.2) is performed 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.
In the simple cases, everything should work as expected. When the construction and initialization of the variable is more complex, there will be risks specific to this case. For instance, if the constructor throws, it will have the opportunity to throw again on the next call. Another example would be recursive initialization which is undefined behavior.
Another possible risk is the performance of the method. The compiler will need to implement a mechanism to ensure compliant initialization of the variable. This is implementation-dependent and it could very well be a lock to check if the variable is initialized, and that lock could be executed every time the method is called. When that happens, it can have a significant adverse effect on performance.
bool SomeClass::Function( bool thankYou = true )
{
static bool justAbool = false;
// Do something with justAbool;
...
}
I have searched around but I can't find anything about this except globals vars or member functions itself.
What does the above do, i.e. what happens, does justAbool keep its value after leaving the scope? Or does it 'remember' the value when it re-enters the scope?
The variable justAbool is initialized to false only once and it is initialized before the function is entered. The value will be remembered after leaving the scope of the function. It is important to note that the value will also be shared by all instances of SomeClass just like a static member variable. The variable justAbool will not be re-initialized if you create a new instance of your class and then call the function again.
static when applied to a local variable gives that variable static storage duration. This means that the justAbool's lifetime lasts to the end of the program rather than to the end of the invocation of the function. It's scope stays the same, it can only be accessed by name in the function, after the declaration appears.
justAbool will be initialized (using the supplied initializer = false) the first time that the function is called. Thereafter it will retain its previous value, it will not be reinitialized when the function is called again.
Here are some fuller details about storage duration and lifetimes, with references to the standard.
If an object has static storage duration, it means that the storage for the object lasts for the duration of the program (beginning to end). (3.7.1 [basic.stc.static])
As a bool is a type without a non-trivial constructor, its lifetime mirrors that of its storage, i.e. it lives from the beginning to the end of the program. (3.8 [basic.life])
All objects with static storage duration (including local objects) are zero-initialized before any other initialization. (6.7/4 [stmt.decl]) [For local objects with an initializer this is fairly academic because there is no way to read their value before their declaration is reached.]
Local objects of POD type with static storage duration initialized with constant-expressions are initialized before their block is entered, otherwise local objects with static storage duration are initialized when control passes through their declaration. (6.7/4 again)
An implementation is permitter, but not required, to perform early initialization in some situations.
The above function does what it does in the comment // Do something with justAbool;.
On a serious note, yes, the static variable (in this case justAbool) inside a function retains it's value even after returning from the function. It gets initialized ONLY ONCE. And each successive calls uses it as if it's a global variable. Its life-time is equal to the end of the program.
int f()
{
static int v = 0;
return ++v;
}
int main()
{
cout << f() << endl;
cout << f() << endl;
cout << f() << endl;
cout << f() << endl;
}
Output:
1
2
3
4
Online Demo : http://www.ideone.com/rvgB5
The justAbool is actually a regular static variable - it exists from the start of the program and is initialized only once. The special thing is that is is known only in this function - if you try and use it outside the function the compiler won't know what it is.
justAbool keeps its value after leaving the scope. What else did you want this code to do exactly?
function level static local variable, the initialization depends on variable types:
POD: initialized before main()
non-POD: initialized the first time, the line in the function is executed.
If a variable is declared as static in a function's scope it is only initialized once and retains its value between function calls. What exactly is its lifetime? When do its constructor and destructor get called?
void foo()
{
static string plonk = "When will I die?";
}
The lifetime of function static variables begins the first time[0] the program flow encounters the declaration and it ends at program termination. This means that the run-time must perform some book keeping in order to destruct it only if it was actually constructed.
Additionally, since the standard says that the destructors of static objects must run in the reverse order of the completion of their construction[1], and the order of construction may depend on the specific program run, the order of construction must be taken into account.
Example
struct emitter {
string str;
emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
~emitter() { cout << "Destroyed " << str << endl; }
};
void foo(bool skip_first)
{
if (!skip_first)
static emitter a("in if");
static emitter b("in foo");
}
int main(int argc, char*[])
{
foo(argc != 2);
if (argc == 3)
foo(false);
}
Output:
C:>sample.exe
Created in foo
Destroyed in foo
C:>sample.exe 1
Created in if
Created in foo
Destroyed in foo
Destroyed in if
C:>sample.exe 1 2
Created in foo
Created in if
Destroyed in if
Destroyed in foo
[0] Since C++98[2] has no reference to multiple threads how this will be behave in a multi-threaded environment is unspecified, and can be problematic as Roddy mentions.
[1] C++98 section 3.6.3.1 [basic.start.term]
[2] In C++11 statics are initialized in a thread safe way, this is also known as Magic Statics.
Motti is right about the order, but there are some other things to consider:
Compilers typically use a hidden flag variable to indicate if the local statics have already been initialized, and this flag is checked on every entry to the function. Obviously this is a small performance hit, but what's more of a concern is that this flag is not guaranteed to be thread-safe.
If you have a local static as above, and foo is called from multiple threads, you may have race conditions causing plonk to be initialized incorrectly or even multiple times. Also, in this case plonk may get destructed by a different thread than the one which constructed it.
Despite what the standard says, I'd be very wary of the actual order of local static destruction, because it's possible that you may unwittingly rely on a static being still valid after it's been destructed, and this is really difficult to track down.
The existing explanations aren't really complete without the actual rule from the Standard, found in 6.7:
The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization 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. 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.
FWIW, Codegear C++Builder doesn't destruct in the expected order according to the standard.
C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if
... which is another reason not to rely on the destruction order!
The Static variables are come into play once the program execution starts and it remain available till the program execution ends.
The Static variables are created in the Data Segment of the Memory.