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;
}
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.