Art*_*ger 692 c++ singleton design-patterns
最近我碰到了C++的Singleton设计模式的实现/实现.看起来像这样(我从现实生活中采用了它):
// a lot of methods are omitted here
class Singleton
{
public:
static Singleton* getInstance( );
~Singleton( );
private:
Singleton( );
static Singleton* instance;
};
Run Code Online (Sandbox Code Playgroud)
从这个声明我可以推断出实例字段是在堆上启动的.这意味着存在内存分配.对我来说完全不清楚的是,什么时候内存将被解除分配?还是有漏洞和内存泄漏?好像在实施中存在问题.
我的主要问题是,如何以正确的方式实施它?
Mar*_*ork 1035
在2008年,我提供了Singleton设计模式的C++ 98实现,它是懒惰评估,保证破坏,非技术上线程安全的:
任何人都可以在c ++中为我提供Singleton样本吗?
这是Singleton设计模式的更新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
};
Run Code Online (Sandbox Code Playgroud)
请参阅此文章,了解何时使用单例:(不经常)
Singleton:如何使用它
请参阅这两篇关于初始化顺序以及如何应对的文章:
静态变量初始化顺序
查找C++静态初始化顺序问题
请参阅本文描述生命周期:
C++函数中静态变量的生命周期是多少?
请参阅本文讨论对单例的一些线程影响:
Singleton实例声明为GetInstance方法的静态变量,它是否是线程安全的?
看到这篇文章解释了为什么双重检查锁定不适用于C++:
C++程序员应该知道的所有常见的未定义行为是什么?
Dobbs博士:C++和双重锁定的危险:第一部分
Ree*_*sey 46
作为一个单身人士,你通常不希望它被破坏.
当程序终止时,它将被拆除并解除分配,这是单例的正常,期望的行为.如果你想能够明确地清理它,那么向类中添加一个静态方法是非常容易的,它允许你将它恢复到干净状态,并在下次使用它时重新分配它,但这超出了范围. "经典"单身人士.
Căt*_*tiș 36
你可以避免内存分配.存在许多变体,在多线程环境的情况下都存在问题.
我更喜欢这种实现(实际上,我没有正确地说我更喜欢,因为我尽可能地避免单身人士):
class Singleton
{
private:
Singleton();
public:
static Singleton& instance()
{
static Singleton INSTANCE;
return INSTANCE;
}
};
Run Code Online (Sandbox Code Playgroud)
它没有动态内存分配.
Gal*_*lik 14
但是,有时会出现多个静态对象,您需要能够保证在使用单例的所有静态对象不再需要它之前不会销毁单例.
在这种情况下,即使在程序结束时调用静态析构函数,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() {}
};
Run Code Online (Sandbox Code Playgroud)
另一种非分配选择:C根据需要创建一个单例,比如类;
singleton<C>()
Run Code Online (Sandbox Code Playgroud)
运用
template <class X>
X& singleton()
{
static X x;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这个和Cătălin的答案在当前的C++中都不是自动线程安全的,而是在C++ 0x中.
有人提到过std::call_once和std::once_flag吗?大多数其他方法 - 包括双重检查锁定 - 都被破坏了。
单例模式实现中的一个主要问题是安全初始化。唯一安全的方法是使用同步屏障来保护初始化序列。但这些障碍本身需要安全地启动。std::once_flag是保证安全初始化的机制。
这是一个简单的实现。
#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;
}
Run Code Online (Sandbox Code Playgroud)
只创建了一个对象,并且每次都返回此对象引用。
SingletonClass instance created!
00915CB8
00915CB8
Run Code Online (Sandbox Code Playgroud)
这里 00915CB8 是单例对象的内存位置,在程序运行期间相同,但(通常!)每次程序运行时都不同。
注意这不是线程安全的。你必须确保线程安全。
接受的答案中的解决方案有一个明显的缺点 - 在控件离开main()函数后调用单例的析构函数.当内部分配一些依赖对象时,可能确实存在问题main.
我试图在Qt应用程序中引入Singleton时遇到了这个问题.我决定,我所有的设置对话框都必须是Singletons,并采用上面的模式.不幸的是,Qt的主类QApplication在main函数堆栈中被分配,并且当没有应用程序对象可用时,Qt禁止创建/销毁对话框.
这就是为什么我更喜欢堆分配的单例.我提供一个明确init()和term()方法,对所有的单身人士和内给他们打电话main.因此,我可以完全控制单身人士创造/毁灭的顺序,而且我保证无论是否有人打电话都会创造单身人士getInstance().
如果要在堆中分配对象,为什么不使用唯一指针.由于我们使用唯一指针,因此内存也将被释放.
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);
Run Code Online (Sandbox Code Playgroud)
我没有在答案中找到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;
}
};
Run Code Online (Sandbox Code Playgroud)
要使用它,只需继承您的类,例如: class Test : public Singleton<Test>
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. These notes (and quotations I give in this answer) were created by my Professor, David Kieras.
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."
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.
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; }
};
// somewhere in code (Singleton.cpp is probably the best place)
// create a global static Singleton_destroyer object
Singleton_destoyer the_destroyer;
Run Code Online (Sandbox Code Playgroud)
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."
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.
// public member function
static Singleton& Singleton::get_instance()
{
static Singleton s;
return s;
}
Run Code Online (Sandbox Code Playgroud)
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."
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."
| 归档时间: |
|
| 查看次数: |
645119 次 |
| 最近记录: |