我一直在阅读很多关于单身人士的信息,他们应该和不应该使用它们,以及如何安全地实施它们。我正在用C ++ 11编写,并且遇到了Meyer对单例的懒惰初始化实现,如this question.中所见
此实施是:
static Singleton& instance()
{
static Singleton s;
return s;
}
我理解这对于SO的其他问题是如何线程安全的,但我不明白的是这实际上是一个单例模式。我用其他语言实现了单例,这些总是像Wikipedia这样的例子:
public class SingletonDemo {
private static volatile SingletonDemo instance = null;
private SingletonDemo() { }
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo .class){
if (instance == null) {
instance = new SingletonDemo ();
}
}
}
return instance;
}
}
当我看第二个例子时,它非常直观,它是一个单例,因为该类拥有对其自身的一个实例的引用,并且只返回该实例。但是,在第一个示例中,我不明白这是如何防止存在对象的两个实例的。所以我的问题是:
感谢您的帮助,
答案 0 :(得分:44)
这是一个单例,因为本地函数的static
存储持续时间意味着程序中只存在该本地的一个实例。
在幕后,这大致可以被认为等同于以下的C ++ 98(甚至可能被编译器模糊地实现):
static bool __guard = false;
static char __storage[sizeof(Singleton)]; // also align it
Singleton& Instance() {
if (!__guard ) {
__guard = true;
new (__storage) Singleton();
}
return *reinterpret_cast<Singleton*>(__storage);
}
// called automatically when the process exits
void __destruct() {
if (__guard)
reinterpret_cast<Singleton*>(__storage)->~Singleton();
}
线程安全位使它变得有点复杂,但它基本上是相同的。
查看C ++ 11的实际实现,每个静态(如上面的布尔值)都有一个保护变量,它也用于障碍和线程。看看Clang的AMD64输出:
Singleton& instance() {
static Singleton instance;
return instance;
}
来自{64}的AMD64上的Ubuntu的Clang 3.0的instance
的AMD64程序集(由http://gcc.godbolt.org/提供):
instance(): # @instance()
pushq %rbp
movq %rsp, %rbp
movb guard variable for instance()::instance(%rip), %al
testb %al, %al
jne .LBB0_3
movl guard variable for instance()::instance, %edi
callq __cxa_guard_acquire
testl %eax, %eax
je .LBB0_3
movl instance()::instance, %edi
callq Singleton::Singleton()
movl guard variable for instance()::instance, %edi
callq __cxa_guard_release
.LBB0_3:
movl instance()::instance, %eax
popq %rbp
ret
您可以看到它引用全局防护,以查看是否需要初始化,使用__cxa_guard_acquire
,再次测试初始化,等等。除了使用AMD64程序集和Itanium ABI中指定的符号/布局外,几乎所有方式都与维基百科发布的版本完全相同。
请注意,如果您运行该测试,则应该为Singleton
提供一个非平凡的构造函数,因此它不是POD,否则优化器将意识到执行所有保护/锁定工作没有意义。
答案 1 :(得分:14)
// Singleton.hpp
class Singleton {
public:
static Singleton& Instance() {
static Singleton S;
return S;
}
private:
Singleton();
~Singleton();
};
这种实现被称为Meyers的Singleton。斯科特迈耶斯说:
“这种方法建立在C ++保证本地静态对象的基础之上 在第一次遇到对象的定义时初始化 在打电话给那个功能时。“......”作为奖励,如果你从不打电话给 函数模拟非本地静态对象,您永远不会产生成本 构建和破坏对象。“
打电话的时候
Singleton& s=Singleton::Instance()
第一次创建对象,并且每次调用Singleton::Instance()
时都会返回相同的对象。
主要问题:
另一种实现称为可靠泄漏的Singleton。
class Singleton {
public:
static Singleton& Instance() {
if (I == nullptr) { I = new Singleton(); }
return *I;
}
private:
Singleton();
~Singleton();
static Singleton* I;
};
// Singleton.cpp
Singleton* Singleton::I = 0;
两个问题: