C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Use optional<T> as though it were T

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Wed, 28 Jun 2023 11:30:05 +0100
On Wed, Jun 28, 2023 at 10:53 AM Breno GuimarĂ£es via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
>
> Then all access to the variable just need to check a boolean (in the hot path) instead of calling an opaque function.
>
> I also don't see the need for a mutex on the initialization. The global call_once flag should be enough. The thread local variable shouldn't need to be atomic either.


Here's what I've got now using a thread_local boolean, and relying on
the once_flag to do all the required synchronisation:

        https://godbolt.org/z/Gavo7vf9G

And here it is copy-pasted:

#include <optional> // optional
#include <mutex> // once_flag, call_once
#include <iostream> // Just for testing: cout, endl
#include <thread> // Just for testing: jthread,
get_id, sleep_for
#include <chrono> // Just for testing: milliseconds

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;

/* Note that the following variable is thread_local */
thread_local bool g_is_initialised = false;

std::once_flag g_flag_for_optional{};

T &Func(void)
{
    std::cout << "- - - Func " << std::this_thread::get_id() << " --- ";

    if ( g_is_initialised )
    {
        std::cout << "true\n";
        return *g_optional.operator->(); // crashes instead of throwing
    }

    std::cout << "false\n";
    std::call_once(g_flag_for_optional, []() { g_optional.emplace(); });

    g_is_initialised = true; // This variable is thread_local

    return *g_optional.operator->(); // crashes instead of throwing
}

#define g_obj (Func())

int main(void)
{
    g_obj.Speak();

    std::jthread mythread( []()
        {
            std::this_thread::sleep_for( std::chrono::milliseconds(20u) );
            g_obj.Speak();
            std::this_thread::sleep_for( std::chrono::milliseconds(105u) );
            g_obj.Speak();
        } );

    std::this_thread::sleep_for( std::chrono::milliseconds(120u) );

    g_obj.Speak();
    g_obj.Speak();
    g_obj.Speak();
}

Received on 2023-06-28 10:30:17