C++ Logo


Advanced search

Destruction order of statically-initialized objects (like std::mutex)

From: Kevin Bracey <kevin_at_[hidden]>
Date: Wed, 23 Oct 2019 19:58:50 +0300
std::mutex has a constexpr constructor, which guarantees a non-local one
is usable during construction of non-local objects.

That's thanks to [basic.start.static]: "Together, zero-initialization
and constant initialization are called static initialization; all other
initialization is dynamic initialization. All static initialization
strongly happens before any dynamic initialization."

But could the same mutex continue to be used during destruction of
non-local objects?

I would have hoped that objects would be destroyed in reverse order, so
that a mutex would be guaranteed to be destroyed after all objects with
dynamic initialisation.

But GCC says no:

#include <iostream>

struct MyMutex
     constexpr MyMutex() = default;
     ~MyMutex() { std::cout << "Destroy MyMutex\n"; }

struct MyDynamic
     MyDynamic() { std::cout << "Construct MyDynamic\n"; }
     ~MyDynamic() { std::cout << "Destroy MyDynamic\n"; }

MyDynamic my_dynamic;
MyMutex my_mutex;

void main() {}

// Output:
// Construct MyDynamic
// Destroy MyMutex
// Destroy MyDynamic

I'm not sure that the standard rules that out. [basic.start.term] says
"If the completion of the constructor or dynamic initialization of an
object with static storage duration strongly happens before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first. [...] If an object
is initialized statically, the object is destroyed in the same order as
if the object was dynamically initialized."

What does that "as if" mean? "Obey the ordering rules for
dynamically-initialised objects, bearing in mind that static objects are
initialised first" or "Schedule destruction based on the order this
would have been dynamically initialised"?

I can see why the latter falls out of an implementation - you just
register the destructor with `__cxa_atexit` at the point you would have
called the constructor during your dynamic initialisation code. But is
it what's intended?

Shouldn't all statically-initialised objects get first dibs on atexit
registration? Otherwise std::mutex's constexpr constructor only does
half the ordering job.


Received on 2019-10-23 12:01:09