This is a nice idiom, but I don't think it deserves to take up space in the standard library.

A better (constexpr-friendly) solution looks something like the following. My understanding is that Peter Dimov invented it, although I failed to turn up any "original implementation" in my Google search, and therefore I may have gotten wrong the details and/or the authorship.
https://godbolt.org/z/LjNqJz

template<class T>
class even_better_no_destructor {
public:
    template<class... Args>
    constexpr even_better_no_destructor(Args&&... args) : t(std::forward<Args>(args)...) {}

    ~even_better_no_destructor() {}
    constexpr T& value() { return t; }

private:
    union {
        char dummy;
        T t;
    };
};

Notice that `no_destructor<T>` acts like a "wrapped T", but certainly not like a "function"; therefore it should not have an `operator()`. The traditional way to unwrap a wrapped T is `.get()` (tuple/variant/unique_ptr/shared_ptr) or `.value()` (optional/expected).

In C++2a, the current expectation is that you'll be able to use the new `constinit` keyword to say
    static constinit no_destructor<A> a;
to eliminate the guard variable and so on. Once any vendor supports `constinit`, it would be interesting to see if it works as expected with this idiom.

–Arthur


On Tue, Aug 13, 2019 at 1:04 PM Walt Karas via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
One approach to the static initialization order problem looks like:

A & a1()
{
static A a;
return(a);
}

The problem is that, if A had a non-trivial destructor, the static order destruction problem could still cause undefined behavior.  A solution to this, avoiding the call to A::~A, is:

A & a2()
{
static A* a(new A);
return(*a);
}

This template, no_destructor,  avoids the destructor call without requiring an unnecessary dynamic allocation:

#include <utility>
#include <new>

template <typename T>
class no_destructor
{
public:

template <typename ... Args>
no_destructor(Args && ... args)
{
new (payload) T(std::forward<Args>(args)...);
}

T & operator () () { return(*reinterpret_cast<T *>(payload)); }

private:

alignas(T) char payload[sizeof(T)];
};

A & a3()
{
static no_destructor<A> a;
return(a());
}

https://godbolt.org/z/cGSXRy


--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals