在这些情况下,我写了下一个Singleton类:
1 - 我想要一个且只有一个类的实例存在并且可以从整个游戏引擎访问
2 - Singleton被密集使用(每帧数千次)所以我不想写一个额外的GetInstance()函数,我试图避免任何额外的函数调用性能
3 - 一种可能性是让GetInstance()像这样内联:
inline Singleton* Singleton::GetInstance()
{
static Singleton * singleton = new Singleton();
return singleton;
}
但这会引起引用问题,每次调用都会有一个对单例的新引用,修复用c ++编写的内容:
class Singleton{
private:
static Singleton* singleton;
Singleton(){}
public:
static inline Singleton* GetInstance() // now can be inlined !
{
return singleton;
}
static void Init()
{
// ofc i have to check first if this function
// is active only once
if(singleton != nullptr)
{
delete singleton;
}
singleton = new Singleton();
}
~Singleton(){} // not virtual because this class can't be inherited
};
Singleton* Singleton::singleton = nullptr;
此实施可能会遇到哪些问题?
答案 0 :(得分:11)
您的第一个实施问题是您呼叫的唯一new
泄漏。
以及强制用户检查指针有效性的签名。
由于您需要使用两步初始化,并且不禁止复制/移动/分配,您的第二个实现会出现更多问题。
只需使用Meyers'单:
class Singleton{
private:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton operator&(const Singleton&) = delete;
public:
static Singleton& GetInstance()
{
static Singleton instance;
return instance;
}
};
答案 1 :(得分:5)
除了@ Jarod42的回答之外,我想指出你也可以通过制作模板来实现一个通用的单例,并在CRTP类中使用它:
template<typename T>
class Singleton {
protected:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton operator&(const Singleton&) = delete;
public:
static T& instance() {
static T instance;
return instance;
}
};
然后扩展它:
struct MySingleton : Singleton<MySingleton> { /* ... */ };
答案 2 :(得分:1)
考虑命名空间而不是单身人士!以下是我将如何做到这一点:
// thing.h
namespace thing {
// public interface
int doSomething();
}
// thing.cpp
namespace thing {
namespace {
// private data and functions can go right here :-)
int private_data_ = 1234;
int doSomethingInternal() {
return private_data_ * 2;
}
}
// public interface
int doSomething() {
return doSomethingInternal();
}
}
用法很简单:
int x = thing::doSomething();
不需要getInstance()
,没有内存泄漏,也不会意外地发生多个实例。
答案 3 :(得分:-2)
但这会引起引用问题,每次调用都会有一个对单例的新引用
不正确的;相反,会有一个新的实例类与引用不同。你最有可能最终泄漏记忆。
static Singleton* singleton;
使用unique_ptr
代替原始指针。编译器优化无论如何都会将它转换为原始指针,但现在你清楚地告诉编译器它的生命周期应该是什么。
class Singleton{
private :
static Singleton* singleton;
类的默认范围是私有的;你不需要说明私人范围。
Singleton(){}
如果类中没有其他构造函数,则无需提供空构造函数。
我试图避免任何额外的函数调用性能
编译的C ++通常会内联这些代码。
inline Singleton* GetInstance() // now can be inlined !
让它静止......?
~Singleton(){} // not virtual because this class can't be inherited
如果您的目的是使其不可继承,则在类声明中添加final
关键字。然后,您可以删除析构函数。