shared_instance implementation using C++ and RAII I created a little singleton-like class that gets deleted when there is no reference to it anymore (so its lifetime shall be somewhat predictable). I aimed to make it thread-safe.

#include &lt;memory&gt;
#include &lt;mutex&gt;

template&lt; typename t_type &gt;
struct shared_instance
{
    static std::shared_ptr&lt; t_type &gt; get_shared_instance()
    {
        static std::weak_ptr&lt; t_type &gt; weak;
        static std::mutex mutex;

        auto result = weak.lock();
        if( nullptr == result )
        {
            std::unique_lock&lt; std::mutex &gt; lock{ mutex };

            result = weak.lock();
            if( nullptr != result )
            {
                return result;
            }

            result = std::make_shared&lt; t_type &gt;();
            weak = result;
        }
        return result;
    }
};

template&lt; typename t &gt;
struct context 
{ 
    context() 
    : instance{ shared_instance&lt; t &gt;::get_shared_instance() } 
    { }

private: std::shared_ptr&lt; t &gt; instance;
};


I would be glad if you could comment on the implementation itself and how I could tackle non-default-constructible objects (I know of perfect forwarding and variadic templates but I have not found an elegant way to evaluate them lazily).
Non-Default Constructors:

Adding support for non-default constructible objects in a "lazy" fashion, could be done by adding a factory function of std::function&lt;std::shared_ptr&lt; t_type &gt;()&gt;.

template&lt; typename t_type &gt;
struct shared_instance
{
    using t_factory = std::function&lt;std::shared_ptr&lt; t_type &gt;()&gt;;

    static t_factory factory; // MUST be set before calling get_shared_instance

    static std::shared_ptr&lt; t_type &gt; get_shared_instance()
    {
        ...


            assert(factory); // or throw, or return empty shared_ptr

            result = factory(); // instead of make_shared

        ...
    }

};

// and define the static member...
template&lt; typename t_type &gt;
typename shared_instance&lt; t_type &gt;::t_factory shared_instance&lt; t_type &gt;::factory;


...

int main()
{
    context&lt;int&gt; c; // not ok... haven't set factory yet!

    // do this before any call to get_shared_instance
    shared_instance&lt;int&gt;::factory = [] () { return std::make_shared&lt;int&gt;(5); }; // store things in the lambda by value, not reference...

    context&lt;int&gt; c; // ok
}


I'm not sure this counts as elegant though, as it gives you a two-step initialization process. This could be fixed by recognising the shared_instance itself as a kind of factory, making its contents non-static, and passing it into the contexts:

template&lt; typename t &gt;
struct context
{
    context(instance_provider&lt; t &gt;&amp; provider): // now it can't be created unless this exists...
        instance{ provider.get_shared_instance() }
    { }

private:

    std::shared_ptr&lt; t &gt; instance;
};

int main()
{
    auto provider = instance_provider&lt;int&gt;([] () { return std::make_shared&lt;int&gt;(5); });

    context&lt;int&gt; c(provider);
}


Further Considerations:

Does the C library you're using say anything about context lifetime itself? (e.g. Winsock reference counts calls to WSAStartup() and WSACleanup() internally, so as long as the calls are paired properly the C library handles cleaning up)

The main feature that this shared_instance class seems to provide is destroying The Instance promptly after the last context is destroyed. RAII itself could be achieved by just storing a unique pointer over the maximum possible lifetime of any contexts, which would be simpler. Is this prompt destruction actually important?

If not, then it's just a singleton, which we either live with, or do the work to pass a pointer or reference to the thing you need where it needs to be.