为什么在 std::call_once 中使用 std::move 后 std::unique_ptr 没有设置为 nullptr? [重复]

问题描述 投票:0回答:0

我已经使用 std::call_once 实现了线程安全的单例模式。我故意使用 std::move 将 std::unique_ptr 移动到 CallOnce 函数中,该函数由 std::call_once 调用。然而,在调用 std::call_once 之后,std::unique_ptr 没有设置为 nullptr。我预计在使用 std::move(pInstance) 之后,pInstance 会变为 nullptr。有人可以解释为什么会这样吗? 它可以作为参考传递,但我很想知道如果我使用 std::move 会发生什么。

另外,我的另一个问题是privGetInstance函数中的pInstance为null,那么当std::call_once被执行并返回时,其内容将与CallOnce函数中的pInstance局部变量相同。怎么可能?

#include <conio.h>
#include <thread>
#include <future>
#include <chrono>

struct ThreadCountProxy
{
public:


    static void Increment() 
    {
        std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
        std::lock_guard<std::mutex> lock(pInstance->mtx);
        ++pInstance->count;
        Debug::out("TC:%d \n", pInstance->count);
    }


    static void Decrement() 
    {
        std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
        std::lock_guard<std::mutex> lock(pInstance->mtx);
        --pInstance->count;
        Debug::out("TC:%d \n", pInstance->count);
        if (pInstance->count == 0)
        {
            pInstance->cv_thread_count.notify_one();
        }

    }
    static void WaitUntilThreadsDone()  
    {
        std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
        std::unique_lock<std::mutex> lock_ct(pInstance->mtx_thread_count);
        pInstance->cv_thread_count.wait(lock_ct);
    }

    //static void CleanUp() //Release the memory
    //{
    //  std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
    //  if (pInstance != nullptr)
    //  {
    //      //delete pInstance;
    //      //pInstance = nullptr;
    //  }
    //}
    ~ThreadCountProxy() = default;

    ThreadCountProxy() :
        count(0), mtx(), mtx_thread_count(), cv_thread_count()
    {

        std::cout << "Default Constructor\n"; //This line shows how many instances are being created! 

    }

private:
    
    static void CallOnce(std::unique_ptr<ThreadCountProxy>&& pInstance)
    {

        
        if (pInstance == nullptr)
        {

            pInstance = std::make_unique<ThreadCountProxy>(); 
        }
    }

    static std::unique_ptr<ThreadCountProxy>& privGetInstance()
    {
        //std::this_thread::sleep_for(3s);
        static std::once_flag flag;
        static std::unique_ptr<ThreadCountProxy> pInstance;
        std::call_once(flag, CallOnce,std::move(pInstance)); 

        //if (pInstance == nullptr)
        //{
        //  std::cout << "It is nullptr\n"; //It is used to test whether the Singleton Pattern is thread-safe and works properly or not
        //}
        return pInstance;
    }


    

    //Shared Data
    int count;
    std::mutex mtx; //This mutex is used for the 'count' variable
    std::mutex               mtx_thread_count; //This mutex is used for the signal
    std::condition_variable  cv_thread_count;
};

class ThreadCount
{
public:
    ThreadCount()
    {
        ThreadCountProxy::Increment();
    }

    ~ThreadCount()
    {
        ThreadCountProxy::Decrement();

    }
};
c++ singleton unique-ptr stdmove non-thread-safe
© www.soinside.com 2019 - 2024. All rights reserved.