You can do:

T& g_obj_fn() {
    static T t;
    return t;
}

#define g_obj (g_obj_fn())

Function local statics do the flag+muted+call_once for you.



Em ter., 27 de jun. de 2023 20:47, Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> escreveu:
I think the most efficient implementation of a "construct on demand"
object would work as follows:

        https://godbolt.org/z/dx6YTKnnj

And here it is copy-pasted:

#include <atomic>                   // atomic
#include <optional>                 // optional
#include <mutex>                    // once_flag, call_once, mutex, lock_guard
#include <iostream>                 // Just for testing: 'cout'
#include <thread>                   // Just for testing: 'jthread'

struct T {
     T(void) { std::cout << "Constructing. . .\n"; }
    ~T(void) { std::cout << "Destroying. . .\n"  ; }
    void Speak(void) { std::cout << "Hi!\n"; }
};

std::optional<T> g_optional;

/* forward declaration of function */ T &Func_PreInit(void);

std::atomic<T &(*)(void)> g_funcptr{ &Func_PreInit };

static std::mutex g_mutex_for_optional;

T &Func_Init(void)
{
    std::cout << "> > > Func_Init\n";

    std::lock_guard mylock(g_mutex_for_optional);

    return g_optional.value();
}

std::once_flag g_flag_for_optional{};

T &Func_PreInit(void)
{
    std::cout << "> > > Func_PreInit\n";

    std::call_once(g_flag_for_optional, []()
        {
            std::lock_guard mylock(g_mutex_for_optional);
            g_optional.emplace();
        });

    g_funcptr.store( &Func_Init );

    std::lock_guard mylock(g_mutex_for_optional);
    return g_optional.value();
}

#define g_obj (g_funcptr.load()())

int main(void)
{
    g_obj.Speak();
    std::jthread mythread( [](){ g_obj.Speak(); } );
    g_obj.Speak();
}
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals