这个单身人士有什么问题吗class
is there anything wrong with this Singleton class
在这种情况下我写了下一个单例 class :
1 - 我希望 class 的一个并且只有一个实例存在并且可以从整个游戏引擎访问。
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;
此实施可能会遇到哪些问题?
您的第一个实施问题是您调用的唯一 new
发生泄漏。
以及强制用户检查指针有效性的签名。
您的第二个实现有更多问题,因为您需要使用两步初始化,并且不要禁止 copy/move/assignment。
简单使用 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;
}
};
but that will cause a reference problem , on each call there will be a new reference to the singleton
不正确;相反,将有一个新的 class 实例 ,它与 引用 不同。您很可能最终会泄漏内存。
static Singleton* singleton;
使用 unique_ptr
而不是原始指针。无论如何,编译器优化会将其转化为原始指针,但现在您清楚地告诉编译器它的生命周期应该是多少。
class Singleton{
private :
static Singleton* singleton;
class 的默认作用域是私有的;你不需要明确地说私有范围。
Singleton(){}
当您在 class.
中没有其他构造函数时,无需提供空构造函数
im trying to avoid any extra function call for performance
编译后的 C++ 通常会内联此类代码。
inline Singleton* GetInstance() // now can be inlined !
让它静态...?
~Singleton(){} // not virtual because this class can't be inherited
如果您的意图是使其不可继承,则在 class 声明中添加一个 final
关键字。然后您可以删除析构函数。
除了@Jarod42 的回答之外,我想指出您还可以通过制作模板并在 CRTP 中使用它来实现通用单例 class:
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> { /* ... */ };
考虑命名空间而不是单例!以下是我的做法:
// 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()
,没有内存泄漏,也不会不小心创建多个实例。
在这种情况下我写了下一个单例 class :
1 - 我希望 class 的一个并且只有一个实例存在并且可以从整个游戏引擎访问。
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;
此实施可能会遇到哪些问题?
您的第一个实施问题是您调用的唯一 new
发生泄漏。
以及强制用户检查指针有效性的签名。
您的第二个实现有更多问题,因为您需要使用两步初始化,并且不要禁止 copy/move/assignment。
简单使用 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;
}
};
but that will cause a reference problem , on each call there will be a new reference to the singleton
不正确;相反,将有一个新的 class 实例 ,它与 引用 不同。您很可能最终会泄漏内存。
static Singleton* singleton;
使用 unique_ptr
而不是原始指针。无论如何,编译器优化会将其转化为原始指针,但现在您清楚地告诉编译器它的生命周期应该是多少。
class Singleton{
private :
static Singleton* singleton;
class 的默认作用域是私有的;你不需要明确地说私有范围。
Singleton(){}
当您在 class.
中没有其他构造函数时,无需提供空构造函数im trying to avoid any extra function call for performance
编译后的 C++ 通常会内联此类代码。
inline Singleton* GetInstance() // now can be inlined !
让它静态...?
~Singleton(){} // not virtual because this class can't be inherited
如果您的意图是使其不可继承,则在 class 声明中添加一个 final
关键字。然后您可以删除析构函数。
除了@Jarod42 的回答之外,我想指出您还可以通过制作模板并在 CRTP 中使用它来实现通用单例 class:
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> { /* ... */ };
考虑命名空间而不是单例!以下是我的做法:
// 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()
,没有内存泄漏,也不会不小心创建多个实例。