c3.Singleton|单例
大约 7 分钟
#include <iostream>
class MyClass {
}
int main() {
MyClass* a = new MyClass();
//Do Someting
delete a;
}
- 默认构造函数 (Default Constructor):
如果没有为类定义任何构造函数,编译器将生成一个无参的默认构造函数。
- 析构函数 (Destructor):
如果没有显式定义析构函数,编译器将生成一个默认的析构函数。用于在对象生命周期结束时进行清理工作,如
~MyClass()
。
- 拷贝构造函数 (Copy Constructor):
如果没有定义自己的拷贝构造函数,编译器将生成一个默认的拷贝构造函数。 通过复制另一个对象来初始化一个新对象,如
MyClass obj1; MyClass obj2 = obj1;
。
- 拷贝赋值运算符 (Copy Assignment Operator):
如果没有定义自己的拷贝赋值运算符,编译器将生成一个默认的拷贝赋值运算符。 用于将一个对象的值复制给另一个对象,例如
MyClass obj1, obj2; obj2 = obj1;
。
class MyClass
{
public:
MyClass() {}
~MyClass() {}
};
类默认是私有的。
#include <iostream>
class MyClass
{
MyClass() {}
public:
~MyClass() {}
};
int main() {
MyClass* a = new MyClass();
return 0;
}
#include <iostream>
class Singleton
{
// 将构造函数私有化
Singleton() {}
public:
// 静态成员函数,用于获取类的唯一实例
static Singleton& getInstance()
{
static Singleton instance;
return instance ;
}
void testfunction()
{
std::cout<<"testfunction"<<std::endl;
}
};
int main()
{
// 获取单例实例
Singleton& singletonInstance = Singleton::getInstance();
singletonInstance.testfunction();
return 0;
}
#include <iostream>
class Singleton
{
// 将构造函数私有化
Singleton() {}
public:
static Singleton* getInstance() {
static Singleton instance;
return &instance;
}
void testfunction() {
std::cout<<"testfunction"<<std::endl;
}
};
int main() {
// 获取单例实例
Singleton* singletonInstance = Singleton::getInstance();
singletonInstance->testfunction();
return 0;
}
也可以改写成动态内存分配创建单例对象(懒汉式),这也是智能指针管理内存的核心思想之一,用户无需关心指针释放时机。
#include <iostream>
class Singleton
{
// 将构造函数私有化
Singleton() {}
public:
static Singleton* getInstance() {
static Singleton* instance = nullptr;
if (instance == nullptr) {
instance = new Singleton;
}
return instance;
}
void testfunction() {
std::cout << "testfunction" << std::endl;
}
~Singleton() {
// 在析构函数中释放动态分配的内存
if (instance != nullptr) {
delete instance;
instance = nullptr;
}
}
};
int main() {
// 获取单例实例
Singleton* singletonInstance = Singleton::getInstance();
singletonInstance->testfunction();
// 在程序结束时,析构函数会被调用,释放动态分配的内存
return 0;
}
注
考虑UE大多数情况下无需多线程使用单例,因此没有考虑线程安全问题。懒汉式天生线程安全,但饿汉式多线程会存在线程安全问题,必要时考虑使用互斥锁、双重检查。
在UE中宁可推荐使用结构体单例也不推荐直接用原生单例
经典模式
GameSingleton.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "GameSingleton.generated.h"
UCLASS(Blueprintable,BlueprintType)
class EXORCIST_API UGameSingleton : public UObject
{
GENERATED_BODY()
private:
UGameSingleton() {}
public:
UFUNCTION(BlueprintCallable)
static UGameSingleton* GetInstance();
public:
UPROPERTY(BlueprintReadWrite)
int32 InstanceCount = 30;
};
GameSingleton.cpp
#include "GameSingleton.h"
UGameSingleton* UGameSingleton::GetInstance()
{
static UGameSingleton* instance=nullptr;
if (instance==nullptr)
{
instance=NewObject<UGameSingleton>();
instance->AddToRoot();
}
return instance;
}
EngineSingleton
GameSingleton.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "GameSingleton.generated.h"
UCLASS(Blueprintable,BlueprintType)
class EXORCIST_API UGameSingleton : public UObject
{
GENERATED_BODY()
private:
UGameSingleton() {}
public:
UFUNCTION(BlueprintCallable)
static UGameSingleton* GetInstance();
public:
UPROPERTY(BlueprintReadWrite)
int32 InstanceCount = 30;
};
GameSingleton.cpp
#include "GameSingleton.h"
UGameSingleton* UGameSingleton::GetInstance()
{
if (GEngine)
{
UGameSingleton* Instance = Cast<UGameSingleton>(GEngine->GameSingleton);
if(Instance)
{
return Instance;
}
}
return nullptr;
}
UGameSingleton* Instance = Cast<UGameSingleton>(GEngine->GameSingleton);//没有设置拿不到对应对象实例指针。
CDOSingleton
MySingleton.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MySingleton.generated.h"
UCLASS(BlueprintType,Blueprintable)
class UMySingleton : public UObject
{
GENERATED_BODY()
public:
UMySingleton(const FObjectInitializer& ObjectInitializer);
UFUNCTION(BlueprintPure, Category=MySingleton)
static UMySingleton* GetInstance();
UFUNCTION(BlueprintCallable, Category=MySingleton)
void SetTestStr(FString InStr);
UFUNCTION(BlueprintCallable, Category=MySingleton)
FString GetTestStr();
private:
FString TestStr;
};
MySingleton.cpp
#include "Singleton.h"
UMySingleton::UMySingleton(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
UMySingleton* UMySingleton::GetInstance()
{
// 大多数情况下CDO不应该被修改(使用GetDefault),这里使用GetMutableDefault返回的是可修改版本。
return GetMutableDefault<UMySingleton>();
}
void UMySingleton::SetTestStr(FString InStr)
{
TestStr = InStr;
}
FString UMySingleton::GetTestStr()
{
return TestStr;
}
GameInstance
Subsystem|子系统
bool UGameUIManagerSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
if (!CastChecked<UGameInstance>(Outer)->IsDedicatedServerInstance())
{
TArray<UClass*> ChildClasses;
GetDerivedClasses(GetClass(), ChildClasses, false);
// Only create an instance if there is no override implementation defined elsewhere
return ChildClasses.Num() == 0;
}
return false;
}