I have implemented a thread safe holder to safely pass data between threads.User can set value many times, but only the first SetIfEmpty call stores the value, then user may read the value many times.template <typename T>class ThreadSafeHolder {public:    ThreadSafeHolder() : is_value_set_(false) {    }    void SetIfEmpty(const T& value) {        std::lock_guard<std::mutex> lock(mutex_);        // memory_order_relaxed is enough because storing to        // `is_value_set_` happens only in `SetIfEmpty` methods        // which are protected by mutex.        if (!is_value_set_.load(std::memory_order_relaxed)) {            new(GetPtr()) T(value);            is_value_set_.store(true, std::memory_order_release);        }    }    void SetIfEmpty(T&& value) {        std::lock_guard<std::mutex> lock(mutex_);        if (!is_value_set_.load(std::memory_order_relaxed)) {            new(GetPtr()) T(std::move(value));            is_value_set_.store(true, std::memory_order_release);        }    }    //! This method might be safely call only if previous `IsEmpty()`    //! call returned `false`.    const T& Get() const {        assert(!IsEmpty());        return *GetPtr();    }    bool IsEmpty() const {        // memory_order_acquire loading to become synchronize with        // memory_order_release storing in `SetIfEmpty` methods.        return !is_value_set_.load(std::memory_order_acquire);    }    ~ThreadSafeHolder() {        if (!IsEmpty()) {            GetPtr()->~T();        }    }private:    T* GetPtr() {        return reinterpret_cast<T*>(value_place_holder_);    }    const T* GetPtr() const {        return reinterpret_cast<const T*>(value_place_holder_);    }    // Reserved place for user data.    char value_place_holder_[sizeof(T)];    // Mutex for protecting writing access to placeholder.    std::mutex mutex_;    // Boolean indicator whether value was set or not.    std::atomic<bool> is_value_set_;};QuestionsIs the code correct in general?Is access to is_value_set_ member properly synchronized?Might be access to is_value_set_ member even more relaxed?ApplicationI wanted to develop such holder to pass active exceptions from worker threads to main thread.Main thread:ThreadSafeHolder<std::exception_ptr> exceptionPtrHolder;// Run many workers.// Join workers.if (!exceptionPtrHolder.IsEmpty()) {    std::rethrow_exception(exceptionPtrHolder.Get());}Worker thread:try {    while (exceptionPtrHolder.IsEmpty()) {        // Do hard work...    }} catch (...) {    exceptionPtrHolder.SetIfEmpty(std::current_exception());}Note about std::promisestd::promise is not suitable here (despite the fact that std::promise::set_value is thread safe) becauseAn exception is thrown if there is no shared state or the shared state already stores a value or exception.
Thread safe holder
c++;c++11;multithreading