Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Local static object and exception

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)

like image 930
LmTinyToon Avatar asked Feb 04 '23 14:02

LmTinyToon


2 Answers

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.

like image 57
Lightness Races in Orbit Avatar answered Feb 16 '23 08:02

Lightness Races in Orbit


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.

like image 29
user7860670 Avatar answered Feb 16 '23 09:02

user7860670