正如标题所述。我该如何创建一个全局可用的类实例(例如,我有一个用于打印的函数对象,我希望有一个单一的全局实例(虽然可以创建更多))。
通过使用常规模式制作单例对象的所有努力都没有解决你问题的第二部分——需要时能够创建更多实例。 单例“模式”非常限制,不过是另一个名字的全局变量而已。
// myclass.h
class MyClass {
public:
MyClass();
void foo();
// ...
};
extern MyClass g_MyClassInstance;
// myclass.cpp
MyClass g_MyClassInstance;
MyClass::MyClass()
{
// ...
}
现在,在任何其他模块中,只需包含myclass.h
并像往常一样使用g_MyClassInstance
。如果您需要进行更多操作,则可以调用准备好的构造函数。
首先,你想要全局变量是一个“代码异味”(Per Martin Fowler的说法)。
但是为了达到你想要的效果,你可以使用一种单例模式的变体。
使用静态函数变量。这意味着变量在使用时才会被创建(这样可以实现懒加载),并且所有变量将按照创建的相反顺序被销毁(因此保证了析构函数会被使用)。
class MyVar
{
public:
static MyVar& getGlobal1()
{
static MyVar global1;
return global1;
}
static MyVar& getGlobal2()
{
static MyVar global2;
return global2;
}
// .. etc
}
std::cout
的观察有何关联。std::cout
是好还是坏?如果它不是坏的,为什么?(注意 - 我认为它不是坏的,因为如果是的话,人们就会想出其他替代方案。) 我不确定单例模式的问题与我的关于std::cout
的观察有何关联。std::cout
是好还是坏?如果它不是坏的,为什么?(注意 - 我认为它不是坏的,因为如果是的话,人们就会想出其他替代方案。) - rr-单例模式是一个不错的设计模式,但它也有自己的缺点。在使用单例模式之前,请先阅读 Miško Hevery 的以下博客。
最简单且具有并发安全性的实现是Scott Meyer的单例模式:
#include <iostream>
class MySingleton {
public:
static MySingleton& Instance() {
static MySingleton singleton;
return singleton;
}
void HelloWorld() { std::cout << "Hello World!\n"; }
};
int main() {
MySingleton::Instance().HelloWorld();
}
请参阅第四个主题这里,了解来自GoF名人John Vlissides的分析。
我更喜欢允许单例模式,但不强制使用它,因此从不隐藏构造函数和析构函数。这已经被提过了,我只是在表达我的支持。
我的方法是,除非我想创建一个真正的单例并隐藏构造函数,否则通常不使用静态成员函数。我的常规做法是这样:
template< typename T >
T& singleton( void )
{
static char buffer[sizeof(T)];
static T* single = new(buffer)T;
return *single;
}
Foo& instance = singleton<Foo>();
为什么不使用T的静态实例而是使用放置new?静态实例提供了构造顺序保证,但没有销毁顺序。大多数对象按照构造的相反顺序进行销毁,但静态和全局变量除外。如果您使用静态实例版本,最终会在main函数结束后出现神秘/间歇性的段错误等问题。
这意味着单例的析构函数永远不会被调用。然而,进程无论如何都会关闭并且资源将被回收。这可能有点难以适应,但请相信目前没有更好的跨平台解决方案。幸运的是,C++0x已经对保证销毁顺序进行了更改,可以解决这个问题。一旦您的编译器支持新标准,只需升级单例函数以使用静态实例即可。
此外,在实际实现中,我使用boost来获取对齐内存,而不是普通的字符数组,但不想使示例复杂化。