在Java中我可以像这样创建一个Singleton(只要它不作为异常抛出):
private static Singleton m_this = new Singleton();
这非常方便,因为它本身就是线程安全的。
我可以在C ++中做类似的事情吗?
答案 0 :(得分:3)
使用线程安全初始化制作单例的一种方法,由C ++ 11标准保证。是:
class SomeSingleton {
public:
static SomeSingleton& instance() {
static SomeSingleton instance_;
return instance_;
}
private:
SomeSingleton() {
...
}
};
这是线程安全的,因为local static variable initialization is thread-safe in C++11。相关的标准文档N3485在第6.7.4节中说明:
这样的变量在控件第一次通过其声明时被初始化;这样的变量在初始化完成后被认为是初始化的。 [...]如果控件在初始化变量时同时进入声明,则并发执行应等待初始化完成。
脚注:
实现不得在执行初始化程序时引入任何死锁。
您可以使用CRTP抽象为一个漂亮的模板基类:
//Singleton template definition
template <typename TDerived>
class Singleton {
static_assert(is_base_of<Singleton, TDerived>::value, "Singleton: unexpected Derived template parameter");
public:
static TDerived& instance() {
static TDerived instance_;
return instance_;
}
protected:
Singleton() {
}
};
// SomeSingleton definition, using the Singleton template
class SomeSingleton : public Singleton<SomeSingleton> {
...
};
答案 1 :(得分:1)
如果通过 Singleton ,则表示真实 singleton(我不确定是否与您举例相同,因为您仍然可以创建第二个Singleton
实例并将其分配给另一个变量),答案是是。您可以使用工厂模式创建单个对象。
class factory;
class singleton{
singleton(){}; // private constructor
friend class factory;
};
class factory{
private:
static std::shared_ptr<singleton> object;
public:
static singleton& getSingleton(){
if(object)
return *object;
object = new singleton;
return *object;
}
};
您可以将factory
成为getSingleton
成员函数,而不是专门的static
课程。只记得创建构造函数singleton
,这样用户就无法创建多个副本。
答案 2 :(得分:1)
此外,除了PawełStawarz给出的答案之外,我还要添加复制构造函数,移动构造函数(C ++ 11),重载赋值运算符和析构函数也应该是私有的。
class singleton{
singleton(){}; // private constructor
~singleton(){}; // private destructor
singleton(const singleton &src){}; // private copy constructor
singleton(const singleton&& src){}; // private move constructor for C++11
singleton& operator = (const singleton& src){return *this;} // private = operator
friend class factory;
};
私有,复制构造函数,移动构造函数(C ++ 11),重载赋值运算符和析构函数不能从外部调用来克隆现有副本,也不能销毁刚刚创建的副本。