我正在尝试在C ++中实现单例。我对这门语言比较陌生,所以请解释一下我是否犯了任何小错误。
以下是我的标题文件:
#pragma once
#include <glad\glad.h>
#include <GLFW\glfw3.h>
#include "Imgui\imgui.h"
#include "imgui_impl_glfw_gl3.h"
class GUI
{
static GUI * instance;
private:
GUI();
public:
static GUI * Instance();
void Init(GLFWwindow * window);
void Loop();
void Draw();
void End();
~GUI();
};
和Class文件的一部分。
GUI::GUI()
{
instance = nullptr;
// static GUI * instance = nullptr;
}
GUI * GUI::Instance()
{
if (nullptr == instance) {
instance = new GUI();
}
return instance;
}
我觉得它应该可行,但是,当我尝试执行时,我收到了这个错误。
我对此很新,所以任何有关我错误的帮助都会受到赞赏。
答案 0 :(得分:1)
实现单例的更简单方法是
GUI * GUI::Instance()
{
static GUI* instance = new GUI();
retune instance;
}
这样做,您不必在GUI类中设置任何字段。
注意:如果您想使用引用而不是指针,请将上面的代码中的星号(*)替换为&符号(&amp;)。
答案 1 :(得分:1)
使用OOP设计和讨论Singleton类型时:主要目标是Singleton是一种Object,在程序或应用程序的运行时间内,您只需要1个对象实例。我通常做的是创建一个Singleton类,它是所有单例类型将继承的基类。我不会显示所有派生类,但我将展示Singleton类:
<强> Singleton.h 强>
#ifndef SINGLETON_H
#define SINGLETON_H
class Singleton {
public:
// Number Of Items In Enum Type Must Match The Number
// Of Items And Order Of Items Stored In s_aSingletons
enum SingletonType {
TYPE_LOGGER = 0, // MUST BE FIRST!
TYPE_SETTINGS,
TYPE_ENGINE,
TYPE_ANIMATION_MANAGER,
TYPE_SHADER_MANAGER,
TYPE_ASSET_STORAGE,
TYPE_AUDIO_MANAGER,
TYPE_FONT_MANAGER,
TYPE_BATCH_MANAGER,
}; // Type
private:
SingletonType m_eType;
public:
virtual ~Singleton();
protected:
explicit Singleton( SingletonType eType );
void logMemoryAllocation( bool isAllocated ) const;
private:
Singleton( const Singleton& c ); // Not Implemnted
Singleton& operator=( const Singleton& c ); // Not Implemented
}; // Singleton
#endif // SINGLETON_H
<强> Singleton.cpp 强>
#include "Singleton.h"
#include "Logger.h"
#include "Settings.h"
struct SingletonInfo {
const std::string strSingletonName;
bool isConstructed;
SingletonInfo( const std::string& strSingletonNameIn ) :
strSingletonName( strSingletonNameIn ),
isConstructed( false )
{}
}; // SingletonInfo
// Order Must Match Types Defined In Singleton::SingeltonType enum
static std::array<SingletonInfo, 9> s_aSingletons = { SingletonInfo( "Logger" ),
SingletonInfo( "Settings" ),
SingletonInfo( "Engine" ),
SingletonInfo( "AnimationManager" ),
SingletonInfo( "ShaderManager" ),
SingletonInfo( "AssetStorage" ),
SingletonInfo( "AudioManager" ),
SingletonInfo( "FontManager" ),
SingletonInfo( "BatchManager" ) };
// ----------------------------------------------------------------------------
// Singleton()
Singleton::Singleton( SingletonType eType ) :
m_eType( eType ) {
bool bSaveInLog = s_aSingletons.at( TYPE_LOGGER ).isConstructed;
try {
if ( !s_aSingletons.at( eType ).isConstructed ) {
// Test Initialization Order
for ( int i = 0; i < eType; ++i ) {
if ( !s_aSingletons.at( i ).isConstructed ) {
throw ExceptionHandler( s_aSingletons.at( i ).strSingletonName + " must be constructued before constructing " + s_aSingletons.at( eType ).strSingletonName, bSaveInLog );
}
}
s_aSingletons.at( eType ).isConstructed = true;
if ( s_aSingletons.at( TYPE_ENGINE ).isConstructed &&
Settings::get()->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
logMemoryAllocation( true );
}
} else {
throw ExceptionHandler( s_aSingletons.at( eType ).strSingletonName + " can only be constructed once.", bSaveInLog );
}
} catch ( std::exception& ) {
// eType Is Out Of Range
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid Singelton Type sepcified: " << eType;
throw ExceptionHandler( strStream, bSaveInLog );
}
} // Singleton
// ----------------------------------------------------------------------------
// ~Singleton()
Singleton::~Singleton() {
if ( s_aSingletons.at( TYPE_ENGINE ).isConstructed &&
Settings::get()->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
logMemoryAllocation( false );
}
s_aSingletons.at( m_eType ).isConstructed = false;
} // ~Singleton
// ----------------------------------------------------------------------------
// logMemoryAllocation()
void Singleton::logMemoryAllocation( bool isAllocated ) const {
if ( isAllocated ) {
Logger::log( "Created " + s_aSingletons.at( m_eType ).strSingletonName );
} else {
Logger::log( "Destroyed " + s_aSingletons.at( m_eType ).strSingletonName );
}
} // logMemoryAllocation
现在上面的类不会直接编译,因为它依赖于来自大型库的其他类对象,但是这是为了演示如何设计或实现Singleton而显示的。
从上面的类声明中可以看出,这个库中有不同类型的对象,这些单元都可以在类的枚举类型中看到,也可以在SingletonInfo对象的静态数组中看到,这是一个包含信息的结构关于在* .cpp文件中找到的Singleton。
所有这些类型:
Logger
Settings
Engine
AnimationManager
ShaderManager
AssetStorage
AudioManager
FontManager
BatchManager
所有单身人士和我的图书馆中只有1个这样的类类型的实例,因为它们都是从上面的类继承的。基类还负责构造这些对象的顺序,因为在创建另一个对象之前可能需要先存在某个对象,并且该类还确保一旦构造了一个对象,就不能再构造该类的另一个实例;它会引发异常。这个类也是线程安全的,因为有几个派生类正在使用多线程进程。
现在,获取类的静态指针的static get()
方法;我没有在基类中实现它。作为单例的每个Derived类实现了它自己的方法,用于返回一个静态指针,该指针在成功创建时设置为它的this
指针。
现在,对于从此继承的派生类,它的静态指针方法看起来就像这样。
<强> Derived.h 强>
#include "Singleton.h"
#ifndef DERIVED_H
#define DERIVED_H
class Derived final : public Singleton {
public:
static Derived* const get();
/*Data Type*/ doSomething( /* ... */ ) { /* ... */ }
};
#endif // DERIVED_H
<强> Derived.cpp 强>
#include "Derived.h"
static Settings* s_pSettings = nullptr;
Settings::Settings() :
Singleton( TYPE_DERIVED ) { // Must also be in the enumerated type and the static array
s_pSettings = this;
}
现在使用这个派生类型:
main.cpp
#include "Derived.h"
#include "SomeOtherClass.h"
int main() {
Derived derived; // Create your singleton Instance.
SomeOtherClass soc( /*some data to initialize or construct*/ );
soc.someFunc( /* ... */ );
return 0;
}
假设SomeOtherClass
使用Derived
并且需要访问其静态指针,这就是人们如何做到的:
<强> SomeOtherClass.h 强>
#ifndef SOMEOTHERCLASS_H
#define SOMEOTHERCLASS_H
class SomeOtherClass {
public:
SomeOtherClass( /* ... */ );
void someFunc( /* ... */ );
// Class Details Here
};
#endif // SOMEOTHER_CLASS_H
<强> SomeOtherClass.cpp 强>
#include "SomeOtherClass.h"
#include "Derived.h"
static Derived* s_pDerived = nullptr;
SomeOtherClass::SomeOtherClass( /* ... */ ) {
s_pDerived = Derived::get(); // Only If Derived Was Already Created First
}
void SomeOtherClass::someFunc( /* ... */ ) {
s_pDerived->doSomething( /* ... */ );
}
现在,对于动态分配的这些派生单例类型的指针,我更喜欢使用std::shared_ptr<>
或std:unique_ptr<>
,具体取决于我的需要。这有助于避免内存泄漏,并且还提供了一种处理动态对象访问和所有权的好方法。
答案 2 :(得分:0)
您需要在标头和实现文件中声明静态实例变量,即
GUI * GUI::instance;
需要位于implementation(cpp)文件中的某个位置。