Home > Software engineering >  How can i make private destructor from singleton using shared_ptr?
How can i make private destructor from singleton using shared_ptr?

Time:07-27

i tested two type of singleton from C 17

first is unique_ptr second is shared_ptr

these have to work with private constructor and destructor cause nobody can't change any instance status

i finaly successed to compose unique_ptr version but shrared is not done

shared_ptr version makes error

error is 'Singleton2::~Singleton2()' is private within this context' { __p->~_Up(); }

how can i make shared_ptr singleton?

here's code

class Singleton1
{
    public:
    static Singleton1& GetInstance() 
    {
        if(!mFlag)
        {
            mFlag = true;
            mSingle = std::make_unique<Singleton1>(Singleton1(1));
        }

        return *mSingle.get();
    }

    private:
    friend std::unique_ptr<Singleton1>::deleter_type;

    Singleton1(int n) 
        : mNum(n)
    {
        std::cout << "this is unique_ptr singleton" << std::endl;   
    }

    ~Singleton1() = default;

    private:
    const int mNum;
    inline static bool mFlag;
    inline static std::unique_ptr<Singleton1> mSingle;
};
class Singleton2
{
    public:
    static Singleton2& GetInstance() 
    {
        if(!mFlag)
        {
            mFlag = true;
            mSingle = std::make_shared<Singleton2>(Singleton2(1));
        }

        return *mSingle.get();
    }

    private:
    Singleton2(int n) 
        : mNum(n)
    {
        std::cout << "this is shared_ptr singleton" << std::endl;   
    }

    ~Singleton2() = default;

    private:
    const int mNum;
    inline static bool mFlag;
    inline static std::shared_ptr<Singleton2> mSingle;
};

int main()
{
    Singleton1& res = Singleton1::GetInstance();
    Singleton2& res = Singleton2::GetInstance();

    return 0;
}

CodePudding user response:

You can use a custom deleter and make that friend of Singleton2:

#include <memory>
#include <iostream>

class Singleton2
{
    struct Deleter {
        void operator()(Singleton2* ptr){ delete ptr;}
    };
    friend Deleter;
    public:
    static Singleton2& GetInstance() 
    {
        if(!mFlag)
        {
            mFlag = true;
            mSingle = std::shared_ptr<Singleton2>(new Singleton2(1),Deleter{});
        }

        return *mSingle.get();
    }

    private:
    Singleton2(int n) 
        : mNum(n)
    {
        std::cout << "this is shared_ptr singleton" << std::endl;   
    }

    ~Singleton2() = default;

    private:
    const int mNum;
    inline static bool mFlag;
    inline static std::shared_ptr<Singleton2> mSingle;
};


int main()
{
    //Singleton1& res = Singleton1::GetInstance();
    Singleton2& res = Singleton2::GetInstance();

    return 0;
}

Live Demo


However, consider to simply make the destructor public. As the pointer is encapsulaed there is no danger of someone accidentally destroying the object. And if they want to do it on purpose, they will find a way, whether the destructor is private or not. private is not a way to prevent someone by all possible means to access the function. Its rather a way to unambigously inform others that they should not play tricks to access the method. And because you do not hand the pointer to the caller, they'd also have to "play tricks" when the destructor is public.


PS: I suggest you to use the Meyers Singleton where the instance is stored as function local static variable. It is thread-safe while your GetInstance is not.

  • Related