C++ 单例设计模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1008019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ Singleton design pattern
提问by Artem Barger
Recently I've bumped into a realization/implementation of the Singleton design pattern for C++. It has looked like this (I have adopted it from the real life example):
最近,我遇到了 C++ 单例设计模式的实现/实现。它看起来像这样(我从现实生活中采用了它):
// a lot of methods are omitted here
class Singleton
{
public:
static Singleton* getInstance( );
~Singleton( );
private:
Singleton( );
static Singleton* instance;
};
From this declaration I can deduce that the instance field is initiated on the heap. That means there is a memory allocation. What is completely unclear for me is when exactly the memory is going to be deallocated? Or is there a bug and memory leak? It seems like there is a problem in the implementation.
从这个声明我可以推断出实例字段是在堆上启动的。这意味着存在内存分配。对我来说完全不清楚的是内存何时会被释放?或者是否存在错误和内存泄漏?执行中好像有问题。
My main question is, how do I implement it in the right way?
我的主要问题是,我如何以正确的方式实施它?
回答by Martin York
In 2008 I provided a C++98 implementation of the Singleton design pattern that is lazy-evaluated, guaranteed-destruction, not-technically-thread-safe:
Can any one provide me a sample of Singleton in c++?
2008 年,我提供了单例设计模式的 C++98 实现,它是惰性求值、保证破坏、非技术线程安全的:
谁能给我提供一个单例在 c++ 中的示例?
Here is an updated C++11 implementation of the Singleton design pattern that is lazy-evaluated, correctly-destroyed, and thread-safe.
这是单例设计模式的更新 C++11 实现,它是惰性求值、正确销毁和线程安全的。
class S
{
public:
static S& getInstance()
{
static S instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
private:
S() {} // Constructor? (the {} brackets) are needed here.
// C++ 03
// ========
// Don't forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
// C++ 11
// =======
// We can use the better technique of deleting the methods
// we don't want.
public:
S(S const&) = delete;
void operator=(S const&) = delete;
// Note: Scott Meyers mentions in his Effective Modern
// C++ book, that deleted functions should generally
// be public as it results in better error messages
// due to the compilers behavior to check accessibility
// before deleted status
};
See this article about when to use a singleton: (not often)
Singleton: How should it be used
请参阅这篇关于何时使用单例的文章:(不经常)
单例:如何使用
See this two article about initialization order and how to cope:
Static variables initialisation order
Finding C++ static initialization order problems
关于初始化顺序和如何处理,请参阅这两篇文章:
静态变量初始化顺序
查找 C++ 静态初始化顺序问题
See this article describing lifetimes:
What is the lifetime of a static variable in a C++ function?
请参阅这篇描述生命周期的文章:
什么是 C++ 函数中静态变量的生命周期?
See this article that discusses some threading implications to singletons:
Singleton instance declared as static variable of GetInstance method, is it thread-safe?
请参阅讨论对单例的一些线程影响的文章:
单例实例声明为 GetInstance 方法的静态变量,是否线程安全?
See this article that explains why double checked locking will not work on C++:
What are all the common undefined behaviours that a C++ programmer should know about?
Dr Dobbs: C++ and The Perils of Double-Checked Locking: Part I
请参阅这篇解释为什么双重检查锁定不适用于 C++ 的文章:
C++ 程序员应该了解的所有常见未定义行为是什么?
Dobbs 博士:C++ 和双重检查锁定的危险:第一部分
回答by Reed Copsey
Being a Singleton, you usually do not want it to be destructed.
作为单身人士,您通常不希望它被破坏。
It will get torn down and deallocated when the program terminates, which is the normal, desired behavior for a singleton. If you want to be able to explicitly clean it, it's fairly easy to add a static method to the class that allows you to restore it to a clean state, and have it reallocate next time it's used, but that's outside of the scope of a "classic" singleton.
当程序终止时,它会被拆除和释放,这是单例正常的、期望的行为。如果您希望能够显式清理它,可以很容易地向类中添加一个静态方法,允许您将其恢复到干净的状态,并在下次使用时重新分配,但这超出了 a 的范围“经典”单身人士。
回答by C?t?lin Piti?
You could avoid memory allocation. There are many variants, all having problems in case of multithreading environment.
您可以避免内存分配。有很多变体,在多线程环境中都有问题。
I prefer this kind of implementation (actually, it is not correctly said I prefer, because I avoid singletons as much as possible):
我更喜欢这种实现(实际上,我更喜欢这种说法并不正确,因为我尽可能避免单例):
class Singleton
{
private:
Singleton();
public:
static Singleton& instance()
{
static Singleton INSTANCE;
return INSTANCE;
}
};
It has no dynamic memory allocation.
它没有动态内存分配。
回答by Galik
@Loki Astari's answeris excellent.
@Loki Astari 的回答非常好。
However there are times with multiple static objects where you need to be able to guarantee that the singletonwill not be destroyed until all your static objects that use the singletonno longer need it.
不过也有与多个静态对象的时间,你需要能够保证该单不会被破坏,直到使用了所有的静态对象的单身不再需要它。
In this case std::shared_ptr
can be used to keep the singletonalive for all users even when the static destructors are being called at the end of the program:
在这种情况下,即使在程序结束时调用静态析构函数,std::shared_ptr
也可用于使所有用户的单例保持活动状态:
class Singleton
{
public:
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
static std::shared_ptr<Singleton> instance()
{
static std::shared_ptr<Singleton> s{new Singleton};
return s;
}
private:
Singleton() {}
};
回答by James Hopkin
Another non-allocating alternative: create a singleton, say of class C
, as you need it:
另一个非分配替代方案:C
根据需要创建一个单例,比如 class :
singleton<C>()
using
使用
template <class X>
X& singleton()
{
static X x;
return x;
}
Neither this nor C?t?lin's answer is automatically thread-safe in current C++, but will be in C++0x.
this 和 C?t?lin 的答案在当前的 C++ 中都不是自动线程安全的,但会在 C++0x 中。
回答by Yuriy
I did not find a CRTP implementation among the answers, so here it is:
我在答案中没有找到 CRTP 实现,所以这里是:
template<typename HeirT>
class Singleton
{
public:
Singleton() = delete;
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
static HeirT &instance()
{
static HeirT instance;
return instance;
}
};
To use just inherit your class from this, like: class Test : public Singleton<Test>
要使用从这里继承您的类,例如: class Test : public Singleton<Test>
回答by SadSido
The solution in the accepted answer has a significant drawback - the destructor for the singleton is called after the control leaves the main()
function. There may be problems really, when some dependent objects are allocated inside main
.
已接受答案中的解决方案有一个明显的缺点——在控件离开main()
函数后调用单例的析构函数。确实可能有问题,当一些依赖对象被分配到main
.
I met this problem, when trying to introduce a Singleton in the Qt application. I decided, that all my setup dialogs must be Singletons, and adopted the pattern above. Unfortunately, Qt's main class QApplication
was allocated on stack in the main
function, and Qt forbids creating/destroying dialogs when no application object is available.
我在尝试在 Qt 应用程序中引入单例时遇到了这个问题。我决定,我所有的设置对话框都必须是单例,并采用了上面的模式。不幸的是,Qt 的主类QApplication
是在main
函数的堆栈上分配的,当没有应用程序对象可用时,Qt 禁止创建/销毁对话框。
That is why I prefer heap-allocated singletons. I provide an explicit init()
and term()
methods for all the singletons and call them inside main
. Thus I have a full control over the order of singletons creation/destruction, and also I guarantee that singletons will be created, no matter whether someone called getInstance()
or not.
这就是为什么我更喜欢堆分配的单例。我为所有单例提供了一个显式init()
和term()
方法,并在内部调用它们main
。因此,我可以完全控制单例创建/销毁的顺序,并且我保证无论是否有人调用,都会创建单例getInstance()
。
回答by riderchap
If you want to allocate the object in heap, why don't use a unique pointer. Memory will also be deallocated since we are using a unique pointer.
如果要在堆中分配对象,为什么不使用唯一指针。由于我们使用的是唯一指针,因此内存也将被释放。
class S
{
public:
static S& getInstance()
{
if( m_s.get() == 0 )
{
m_s.reset( new S() );
}
return *m_s;
}
private:
static std::unique_ptr<S> m_s;
S();
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
};
std::unique_ptr<S> S::m_s(0);
回答by Tunvir Rahman Tusher
Here is an easy implementation.
这是一个简单的实现。
#include <Windows.h>
#include <iostream>
using namespace std;
class SingletonClass {
public:
static SingletonClass* getInstance() {
return (!m_instanceSingleton) ?
m_instanceSingleton = new SingletonClass :
m_instanceSingleton;
}
private:
// private constructor and destructor
SingletonClass() { cout << "SingletonClass instance created!\n"; }
~SingletonClass() {}
// private copy constructor and assignment operator
SingletonClass(const SingletonClass&);
SingletonClass& operator=(const SingletonClass&);
static SingletonClass *m_instanceSingleton;
};
SingletonClass* SingletonClass::m_instanceSingleton = nullptr;
int main(int argc, const char * argv[]) {
SingletonClass *singleton;
singleton = singleton->getInstance();
cout << singleton << endl;
// Another object gets the reference of the first object!
SingletonClass *anotherSingleton;
anotherSingleton = anotherSingleton->getInstance();
cout << anotherSingleton << endl;
Sleep(5000);
return 0;
}
Only one object created and this object reference is returned each and every time afterwords.
只创建了一个对象,并且每次都返回此对象引用。
SingletonClass instance created!
00915CB8
00915CB8
Here 00915CB8 is the memory location of singleton Object, same for the duration of the program but (normally!) different each time the program is run.
这里 00915CB8 是单例对象的内存位置,在程序运行期间相同,但(通常!)每次程序运行时都不同。
N.B. This is not a thread safe one.You have to ensure thread safety.
注意这不是线程安全的。你必须确保线程安全。
回答by Tony Bai
We went over this topic recently in my EECS class. If you want to look at the lecture notes in detail, visit http://umich.edu/~eecs381/lecture/IdiomsDesPattsCreational.pdf
我们最近在我的 EECS 课上讨论了这个话题。如果你想详细看讲义,请访问http://umich.edu/~eecs381/lecture/IdiomsDesPattsCreational.pdf
There are two ways that I know to create a Singleton class correctly.
我知道有两种方法可以正确创建单例类。
First Way:
第一种方式:
Implement it similar to the way you have it in your example. As for destruction, "Singletons usually endure for the length of the program run; most OSs will recover memory and most other resources when a program terminates, so there is an argument for not worrying about this."
以类似于您在示例中的方式实现它。至于销毁,“Singleton 通常会在程序运行的时间内持续存在;大多数操作系统会在程序终止时恢复内存和大多数其他资源,因此有理由不必担心这一点。”
However, it is good practice to clean up at program termination. Therefore, you can do this with an auxiliary static SingletonDestructor class and declare that as a friend in your Singleton.
但是,在程序终止时进行清理是一种很好的做法。因此,您可以使用辅助静态 SingletonDestructor 类来执行此操作,并将其声明为您的 Singleton 中的朋友。
class Singleton {
public:
static Singleton* get_instance();
// disable copy/move -- this is a Singleton
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
friend class Singleton_destroyer;
private:
Singleton(); // no one else can create one
~Singleton(); // prevent accidental deletion
static Singleton* ptr;
};
// auxiliary static object for destroying the memory of Singleton
class Singleton_destroyer {
public:
~Singleton_destroyer { delete Singleton::ptr; }
};
The Singleton_destroyer will be created on program startup, and "when program terminates, all global/static objects are destroyed by the runtime library shutdown code (inserted by the linker), so the_destroyer will be destroyed; its destructor will delete the Singleton, running its destructor."
Singleton_destroyer 将在程序启动时创建,“当程序终止时,所有全局/静态对象都被运行时库关闭代码(由链接器插入)销毁,因此 the_destroyer 将被销毁;它的析构函数将删除 Singleton,运行其破坏者。”
Second Way
第二种方式
This is called the Meyers Singleton, created by C++ wizard Scott Meyers. Simply define get_instance() differently. Now you can also get rid of the pointer member variable.
这称为 Meyers Singleton,由 C++ 向导 Scott Meyers 创建。只需以不同的方式定义 get_instance()。现在您还可以摆脱指针成员变量。
// public member function
static Singleton& Singleton::get_instance()
{
static Singleton s;
return s;
}
This is neat because the value returned is by reference and you can use .
syntax instead of ->
to access member variables.
这很好,因为返回的值是通过引用的,您可以使用.
语法而不是->
访问成员变量。
"Compiler automatically builds code that creates 's' first time through the declaration, not thereafter, and then deletes the static object at program termination."
“编译器通过声明自动构建第一次创建 's' 的代码,之后不会,然后在程序终止时删除静态对象。”
Note also that with the Meyers Singleton you "can get into very difficult situation if objects rely on each other at the time of termination - when does the Singleton disappear relative to other objects? But for simple applications, this works fine."
另请注意,使用 Meyers Singleton,“如果对象在终止时相互依赖,您可能会陷入非常困难的境地——Singleton 何时相对于其他对象消失?但对于简单的应用程序,这很好用。”