I'm using a function static variable that I want to initialize once by calling a setter:
void foo() {
static Obj obj;
obj.setName("name"); // this should be called once
// use obj
}
I don't want the setter to be called multiple times, also due to multi threading issues and I can't add a constructor to Obj since I don't own the code. So is this reasonable and thread safe:
void foo() {
static Obj obj = []() {
Obj o;
o.setName("name");
return o;
}();
// use obj
}
Yes, it's thread safe. Quoting n3337 - [stmt.dcl]/4, emphasis mine:
...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.
You perform copy initialization from a lambda's return value, but it's immaterial. The paragraph above doesn't constrain the initialization of obj to be value or direct initialization. All forms of initialization are applicable.
And as a side note, if you must contend with such poorly written types, I'd argue your solution is very idiomatic. It doesn't artificially introduce a new named function to perform the initialization. Instead it keeps initialization code localized. That is a good thing in my book.
Related
class IA
{
public:
virtual void Print() = 0;
}
IA* GetA();
class A : public IA
{
public:
int num = 10;
A()
{
GetA()->Print();
}
void Print()
{
std::cout << num << std::endl;
}
}
IA* GetA()
{
static A a;
return &a;
}
int main()
{
GetA();
std::cout << "End" << std::endl;
getchar();
return 0;
}
Obviously, class A's constructor function calls itself.
"static A a" will get stuck in a loop.
On VS2013, this code can get out from the loop and print "End" on the console.
On VS2017, this code gets stuck in a loop.
**What does VS2013 do for this code?
Nothing in particular has to happen. According to the C++ standard:
[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. [ Example:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
— end example ]
The statement I emboldened is exactly what happens in your program. It's also what the standard's example shows as undefined. The language specification says an implementation can do whatever it deems appropriate. So it could cause an infinite loop, or it may not, depending on the synchronization primitives your implementation uses to prevent concurrent reentry into the block (the initialization has to be thread safe).
Even before C++11, the behavior of recursive reentry was undefined. An implementation could do anything to make sure an object is initialized only once, which in turn could produce different results.
But you can't expect anything specific to happen portably. Not to mention undefined behavior always leaves room for a small chance of nasal demons.
The behaviour is undefined. The reason it "worked" in Visual Studio 2013 is that it didn't implement thread safe initialisation of function statics. What is probably happening is that the first call to GetA() creates a and calls the constructor. The second call to GetA() then just returns the partially constructed a. As the body of your constructor doesn't initialise anything calling Print() doesn't crash.
Visual Studio 2017 does implement thread safe initialisation. and presumably locks some mutex on entry to GetA() if a is not initialised, the second call to GetA() then encounters the locked mutex and deadlocks.
Note in both cases this is just my guess from the observed behaviour, the actual behaviour is undefined, for example GetA() may end up creating 2 instances of A.
How should I work with exceptions throwed from constructors of local static objects? For example I have following code:
class A
{
public:
A() {throw runtime_error("Ooops");}
};
void foo()
{
static A a = A();
cout << "Continue" << endl;
}
int main(void)
{
try
{
foo();
}
catch(...)
{
}
foo(); // Prints continue
return 0;
}
As I understand, in the case of second calling foo method, object a is treated as fully constructed object, and constructor is not called. (More over, it seems like destructor of a due first exception throwing is not called)
If that's true, then that is a compiler bug.
(However, VTT claims that this code produces the expected result with Visual Studio 2015, so I recommend double-checking your results.)
Here's the standard-mandated behaviour:
[C++14: 6.7/4]: 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. [..]
GCC 6.3.0 correctly attempts to reconstruct the A (and thus throws again).
More over, it seems like destructor of a due first exception throwing is not called
No, it won't be. You can't destroy an object that was never successfully created in the first place.
[C++14: 15.2/2]: An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.
By the way, this doesn't fix the problem, but you should just write:
static A a;
The copy-initialisation from a temporary is pointless.
Each instance of static local variable also implicitly creates a global Boolean variable that will be set to true after static variable is constructed. If constructor throws than the next time method is called there will be another attempt to construct a static variable.
The following is adapted from a code:
void func()
{
static MyClass a = init_func();
a_global_var = null;
}
Does C++ compiler guarantees that the first assignment is before the 2nd?
Yes. But I shudder to think why you need to rely on this.
The first time the function is called, a is initialized with whatever is returned from init_func before a_global_var is later set to "null"
Note that as a is static, this only happens the first time the function is called. All subsequent times, a_global_var is set to null without any change to a by this function.
The first line is not an "assignment". It is an initialization. Since it is an initialization of a static object declared in block scope, it will be performed only once, when the control passes over it for the very first time, i.e. when you call your function for the first time.
The second line is indeed an assignment. It will be executed every time the control passes over it, i.e. every time you call your function.
This means that your question only makes sense for the first time this function is called. In that case the initialization is guaranteed to precede the assignment. In all subsequent calls the question will not apply at all, since the initialization will not be performed anymore.
"Does C++ compiler guarantees that the first assignment is before the 2nd?"
Yes, it's guaranteed.
Anyway you should consider to handle this in a singleton (if you really need to have it globally accessible):
class MyClass {
public:
static MyClass& instance() { // <<< replaces func()
static MyClass a;
return a;
}
void* global_var() { return a_global_var; }
private:
MyClass() : a_global_var(nullptr) { // <<< replaces init_func()
}
void* a_global_var;
};
If I have
atomic<int> cnt=0;
int get_int() noexcept
{
cnt++;
return rand();
}
and then:
void func()
{
static const auto value = get_int();
}
I know that there will be no race condition on initialization of value, but I don't know if
get_int() will be called once, or in my example will cnt be 1 (and not 2, 3, 4, or 5).
Assume multiple threads enter func() and get_int has only 1 callsite in func().
C++11 guarantees that there will be no race condition N3797 - §6.7/4:
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.92 If control re-enters the declaration recursively while the variable is being
initialized, the behavior is undefined. [ Example:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
- end example ]
It's not re-entrant but thread-safe. Make sure there will not be other parts of the code that will call get_int() before func() anyway.
get_int() will be called only once from that line , but given your code, get_int() could be called beforehand from different locations in the code.
I have done little work in multi-threaded environments. So, I need to know whether below class's getInstance function is thread-safe or not. Here is singleton class :
//Singleton class
class S {
// intentionally avoided pointer
static S singleObject;
// Private constructor
s ();
s (S &);
s& operator= (const s&);
public:
// return reference of static object
s& getInstance ()
{
return singleObject;
}
/* Normally with static pointer instance, getInstnace look like as
s& getInstace ()
{
// trying to avoid multiple copies of singleObject
lock_mutex ()
if (singleObject == null)
singleObjecct = new S();
unlock_mutex ();
return *singleObject;
}
*/
};
S S::singleObject;
In getInstance function (un-commented), static object's reference is returned. Does it requires thread-safe mechanism?
In second getInstance (commented), we create the object if singleObject is null. So, it requires a locking mechanism and needs to be synchronized, right?
In getInstance function (un-commented), static object's reference is returned. Does it requires thread-safe mechanism?
As long as you don't access it outside the lifetime of the main function, or modify it when other threads might have unsynchronised access, then it's safe to access from any thread.
If you do access before main starts or after it ends (e.g. from the constructor or destructor of another static object), then there is a danger that it won't have been initialised, or will already have been destroyed, at that point. That is the motivation for "lazy initialisation" such as your second version.
In second getInstance (commented), we create the object if singleObject is null. So, it requires a locking mechanism and needs to be synchronized, right?
Yes, that requires a locking mechanism. For compilers that support the C++11 (or similar) threading model, a simpler way to get lazy initialisation like this is to use a function-static variable, which will be initialised in a thread-safe way the first time it comes into scope:
S& getInstance ()
{
static S singleObject;
return singleObject;
}
This will also avoid the memory leak of your version, but introduces a danger that it might be destroyed before other static objects; therefore, it's not safe to access from a static object's destructor.
In general, static objects in C++ are a minefield of such deathtraps (whether or not you try to wrap them up in some kind of singleton anti-pattern) and are best avoided.
In C++11 you can place static instance inside a static function:
class S
{
private:
S();
S(S const&);
S& operator=(S const&);
public:
static S& getInstance ()
{
static S singleObject;
return singleObject;
}
};
According to paragraph 6.7.4 of the Standard:
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.
Unless you declare getInstance as static you won't be able to call it. This mistake has propagated almost to all replies. Other than this, I can't add anything better to all the answers.
IIRC this is better for more than this reason. It won't initialize (thread safely) until getInstance is called.
-edit- I remember some reasons now. You can't get access unless that method is called. You can call this in other class constructors and wont need to worry if S has been initialized or no. As in the other class may be constructed first in which case a crash or undefined behavior occurs.
//Singleton class
class S {
// intentionally avoided pointer
// Private constructor
s ();
s (S &);
s& operator= (const s&);
public:
// return reference of static object
s& getInstance ()
{
static S singleObject;
return singleObject;
}
};