我有我的单例类,它返回指向实例的本地静态的指针以确保线程安全。现在,如果我没有将析构函数声明为私有,那么用户可以将其删除吗?
对于前。
class Singleton
{
Singleton();
public:
static Singleton *getInstance();
};
Singleton *Singleton::getInstance()
{
static Singleton inst;
return &inst;
}
// in user code
void foo()
{
Singleton *inst = Singleton::getInstance();
// do its stuff
//accidentally delete instance here?!
// Should I have private destructor?
delete inst;
}
答案 0 :(得分:5)
如果在析构函数设置为私有的情况下尝试删除foo
中的指针,则会导致编译错误,因为析构函数不可访问。如果在delete
的成员或朋友中调用了Singleton
,那么它仍然会编译。这就是说delete
未使用new
分配的指针是未定义的行为,因此我们应该尝试将其设置为用户不会偶然尝试调用delete
的位置。
可以阻止这种情况的一种方法是返回引用而不是指针。这样,您的用户甚至不会尝试调用delete
,因为他们正在处理非指针类型。
class Singleton
{
Singleton() {};
public:
static Singleton& getInstance();
};
Singleton& Singleton::getInstance()
{
static Singleton inst;
return inst;
}
答案 1 :(得分:3)
getInstance
函数返回Singleton&
而不是Singleton*
,也不会阻止类的用户执行以下操作,从而调用未定义的行为 :
auto& singleton = Singleton::getInstance();
delete &singleton; // undefined behaviour
如果你将析构函数设为私有,他们可以尝试使用这样的恶意代码来抛弃该限制:
delete (void*)(&singleton); // undefined behaviour
事实上,他们也可能试图在指针上调用free
,这更加邪恶:
free(&singleton); // undefined behaviour
如果函数返回指针,你可能会认为这样的事故更可能 。然后,经验丰富的C ++开发人员再也不会尝试delete
或free
某些东西,而不会仔细检查它是否安全且必要;我会说如果你必须处理那些试图明确删除从Singleton实例函数返回的东西的程序员,那么无论如何你都会遇到更大的代码质量问题。
话虽如此,通过使getInstance
返回指针或使析构函数非私有,没有任何结果。通过返回引用而不是指针并使析构函数变为私有,您只需要牺牲一点安全奖励和一些额外的可读性。
答案 2 :(得分:1)
现在,如果我没有将析构函数声明为私有,那么用户可以将其删除吗?
是的,用户可以将其删除。
确保他们不容易这样做是你的工作(一个坚定的用户意图颠覆你的意图会找到一种方法)。您可以采取的方向:
private
。getInstance()
的返回类型以返回参考。class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton theInstance;
return theInstance;
}
private:
Singleton(){}
~Singleton(){}
};