From a09c344bb74d160994f1e1f48ac78ea84f4a7f49 Mon Sep 17 00:00:00 2001 From: Lenheart <947330670@qq.com> Date: Tue, 17 Mar 2026 04:50:15 +0800 Subject: [PATCH] =?UTF-8?q?refactor(base):=20=E5=BC=95=E5=85=A5=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E8=AE=A1=E6=95=B0=E6=99=BA=E8=83=BD=E6=8C=87=E9=92=88?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=9B=BF=E6=8D=A2std::shared=5Fptr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增RefObject基类实现引用计数功能 - 新增RefPtr智能指针模板类 - 修改Texture和Shader类继承自RefObject - 替换原有std::shared_ptr为RefPtr - 更新相关代码中的指针操作 --- .../include/frostbite2D/base/Noncopyable.h | 14 ++ .../include/frostbite2D/base/RefObject.h | 24 +++ Frostbite2D/include/frostbite2D/base/RefPtr.h | 39 ++++ Frostbite2D/include/frostbite2D/base/base.h | 4 + .../include/frostbite2D/core/RefBasePtr.hpp | 178 ++++++++++++++++++ .../include/frostbite2D/graphics/shader.h | 5 +- .../include/frostbite2D/graphics/texture.h | 6 +- .../include/frostbite2D/types/type_alias.h | 10 +- .../src/frostbite2D/base/RefObject.cpp | 24 +++ .../src/frostbite2D/graphics/batch.cpp | 6 +- .../frostbite2D/graphics/shader_manager.cpp | 2 +- 11 files changed, 298 insertions(+), 14 deletions(-) create mode 100644 Frostbite2D/include/frostbite2D/base/Noncopyable.h create mode 100644 Frostbite2D/include/frostbite2D/base/RefObject.h create mode 100644 Frostbite2D/include/frostbite2D/base/RefPtr.h create mode 100644 Frostbite2D/include/frostbite2D/base/base.h create mode 100644 Frostbite2D/include/frostbite2D/core/RefBasePtr.hpp create mode 100644 Frostbite2D/src/frostbite2D/base/RefObject.cpp diff --git a/Frostbite2D/include/frostbite2D/base/Noncopyable.h b/Frostbite2D/include/frostbite2D/base/Noncopyable.h new file mode 100644 index 0000000..3997587 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/base/Noncopyable.h @@ -0,0 +1,14 @@ +#pragma once + +namespace frostbite2D { + +class Noncopyable { +protected: + Noncopyable() = default; + +private: + Noncopyable(const Noncopyable&) = delete; + Noncopyable& operator=(const Noncopyable&) = delete; +}; + +} diff --git a/Frostbite2D/include/frostbite2D/base/RefObject.h b/Frostbite2D/include/frostbite2D/base/RefObject.h new file mode 100644 index 0000000..574cfd9 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/base/RefObject.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace frostbite2D { + +class RefObject : protected Noncopyable { +public: + void Retain(); + void Release(); + uint32_t GetRefCount() const; + + virtual ~RefObject(); + +protected: + RefObject(); + +private: + std::atomic ref_count_; +}; + +} diff --git a/Frostbite2D/include/frostbite2D/base/RefPtr.h b/Frostbite2D/include/frostbite2D/base/RefPtr.h new file mode 100644 index 0000000..fd6cf78 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/base/RefPtr.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +namespace frostbite2D { + +struct DefaultRefPtrPolicy { + void Retain(RefObject* ptr) { + if (ptr) { + ptr->Retain(); + } + } + + void Release(RefObject* ptr) { + if (ptr) { + ptr->Release(); + } + } +}; + +template +using RefPtr = RefBasePtr; + +template +RefPtr MakePtr(Args&&... args) { + static_assert(std::is_base_of::value, + "T must be derived from RefObject"); + return RefPtr(new T(std::forward(args)...)); +} + +template +RefPtr MakePtr(T* ptr) { + static_assert(std::is_base_of::value, + "T must be derived from RefObject"); + return RefPtr(ptr); +} + +} diff --git a/Frostbite2D/include/frostbite2D/base/base.h b/Frostbite2D/include/frostbite2D/base/base.h new file mode 100644 index 0000000..8edeb80 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/base/base.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/Frostbite2D/include/frostbite2D/core/RefBasePtr.hpp b/Frostbite2D/include/frostbite2D/core/RefBasePtr.hpp new file mode 100644 index 0000000..f63e45c --- /dev/null +++ b/Frostbite2D/include/frostbite2D/core/RefBasePtr.hpp @@ -0,0 +1,178 @@ +#pragma once + +#include +#include + +namespace frostbite2D { + +template +class RefBasePtr : protected RefPolicy { +public: + using value_type = T; + using pointer_type = T*; + using const_pointer_type = const T*; + using reference_type = T&; + using const_reference_type = const T&; + + RefBasePtr() noexcept : ptr_(nullptr) {} + RefBasePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} + + RefBasePtr(pointer_type p) : ptr_(p) { + RefPolicy::Retain(ptr_); + } + + RefBasePtr(const RefBasePtr& other) : ptr_(other.ptr_) { + RefPolicy::Retain(ptr_); + } + + RefBasePtr(RefBasePtr&& other) noexcept : ptr_(nullptr) { + Swap(other); + } + + ~RefBasePtr() { + Tidy(); + } + + template ::value, int>::type = 0> + RefBasePtr(const RefBasePtr& other) { + ptr_ = dynamic_cast(other.Get()); + RefPolicy::Retain(ptr_); + } + + pointer_type Get() const noexcept { return ptr_; } + + pointer_type* GetAddressOfAndRelease() { + Tidy(); + return &ptr_; + } + + void Reset(pointer_type ptr = nullptr) { + if (ptr) { + RefBasePtr(ptr).Swap(*this); + } else { + Tidy(); + } + } + + void Swap(RefBasePtr& other) noexcept { + std::swap(ptr_, other.ptr_); + } + + pointer_type operator->() { return ptr_; } + const_pointer_type operator->() const { return ptr_; } + reference_type operator*() { return *ptr_; } + const_reference_type operator*() const { return *ptr_; } + pointer_type* operator&() { return this->GetAddressOfAndRelease(); } + + operator bool() const noexcept { return ptr_ != nullptr; } + bool operator!() const noexcept { return ptr_ == nullptr; } + + RefBasePtr& operator=(const RefBasePtr& other) { + if (other.ptr_ != ptr_) { + RefBasePtr(other).Swap(*this); + } + return *this; + } + + RefBasePtr& operator=(RefBasePtr&& other) noexcept { + if (other.ptr_ != ptr_) { + other.Swap(*this); + } + return *this; + } + + RefBasePtr& operator=(pointer_type p) { + if (p != ptr_) { + RefBasePtr(p).Swap(*this); + } + return *this; + } + + template ::value, int>::type = 0> + RefBasePtr& operator=(const RefBasePtr& other) { + if (other.Get() != ptr_) { + RefBasePtr(dynamic_cast(other.Get())).Swap(*this); + } + return *this; + } + + RefBasePtr& operator=(std::nullptr_t) { + Tidy(); + return *this; + } + +private: + void Tidy() { + RefPolicy::Release(ptr_); + ptr_ = nullptr; + } + + pointer_type ptr_; +}; + +template +bool operator==(const RefBasePtr& lhs, + const RefBasePtr& rhs) noexcept { + return lhs.Get() == rhs.Get(); +} + +template +bool operator==(const RefBasePtr& lhs, T* rhs) noexcept { + return lhs.Get() == rhs; +} + +template +bool operator==(T* lhs, const RefBasePtr& rhs) noexcept { + return lhs == rhs.Get(); +} + +template +bool operator==(const RefBasePtr& lhs, std::nullptr_t) noexcept { + return !static_cast(lhs); +} + +template +bool operator==(std::nullptr_t, const RefBasePtr& rhs) noexcept { + return !static_cast(rhs); +} + +template +bool operator!=(const RefBasePtr& lhs, + const RefBasePtr& rhs) noexcept { + return !(lhs == rhs); +} + +template +bool operator!=(const RefBasePtr& lhs, T* rhs) noexcept { + return lhs.Get() != rhs; +} + +template +bool operator!=(T* lhs, const RefBasePtr& rhs) noexcept { + return lhs != rhs.Get(); +} + +template +bool operator!=(const RefBasePtr& lhs, std::nullptr_t) noexcept { + return static_cast(lhs); +} + +template +bool operator!=(std::nullptr_t, const RefBasePtr& rhs) noexcept { + return static_cast(rhs); +} + +template +bool operator<(const RefBasePtr& lhs, + const RefBasePtr& rhs) noexcept { + return lhs.Get() < rhs.Get(); +} + +template +void swap(RefBasePtr& lhs, RefBasePtr& rhs) noexcept { + lhs.Swap(rhs); +} + +} diff --git a/Frostbite2D/include/frostbite2D/graphics/shader.h b/Frostbite2D/include/frostbite2D/graphics/shader.h index c8386c7..664488c 100644 --- a/Frostbite2D/include/frostbite2D/graphics/shader.h +++ b/Frostbite2D/include/frostbite2D/graphics/shader.h @@ -2,12 +2,13 @@ #include #include +#include #include #include namespace frostbite2D { -class Shader { +class Shader : public RefObject { public: Shader() = default; ~Shader(); @@ -28,7 +29,7 @@ public: void setMat4(const std::string& name, const glm::mat4& value); void setTexture(const std::string& name, int slot); -private: + private: Shader(const std::string& name, uint32_t programID); friend class ShaderManager; diff --git a/Frostbite2D/include/frostbite2D/graphics/texture.h b/Frostbite2D/include/frostbite2D/graphics/texture.h index c34a77b..2effc02 100644 --- a/Frostbite2D/include/frostbite2D/graphics/texture.h +++ b/Frostbite2D/include/frostbite2D/graphics/texture.h @@ -2,12 +2,13 @@ #include #include +#include #include #include namespace frostbite2D { -class Texture { +class Texture : public RefObject { public: static Ptr loadFromFile(const std::string& path); static Ptr createFromMemory(uint8* data, int width, int height, int channels); @@ -29,9 +30,6 @@ public: private: Texture(int width, int height, uint32_t id); - friend class std::shared_ptr; - template friend Ptr makePtr(Args &&...args); - uint32_t textureID_ = 0; int width_ = 0; int height_ = 0; diff --git a/Frostbite2D/include/frostbite2D/types/type_alias.h b/Frostbite2D/include/frostbite2D/types/type_alias.h index dba4af4..9fc66e9 100644 --- a/Frostbite2D/include/frostbite2D/types/type_alias.h +++ b/Frostbite2D/include/frostbite2D/types/type_alias.h @@ -4,6 +4,8 @@ #include #include +#include + namespace frostbite2D { // --------------------------------------------------------------------------- @@ -15,8 +17,8 @@ namespace frostbite2D { // --------------------------------------------------------------------------- // 智能指针别名 // --------------------------------------------------------------------------- -template using Ptr = std::shared_ptr; -template using SharedPtr = std::shared_ptr; +template using Ptr = RefPtr; +template using SharedPtr = RefPtr; template using UniquePtr = std::unique_ptr; @@ -24,12 +26,12 @@ template using WeakPtr = std::weak_ptr; /// 创建 shared_ptr 的便捷函数 template inline Ptr makePtr(Args &&...args) { - return std::make_shared(std::forward(args)...); + return MakePtr(std::forward(args)...); } template inline SharedPtr makeShared(Args &&...args) { - return std::make_shared(std::forward(args)...); + return MakePtr(std::forward(args)...); } /// 创建 unique_ptr 的便捷函数 diff --git a/Frostbite2D/src/frostbite2D/base/RefObject.cpp b/Frostbite2D/src/frostbite2D/base/RefObject.cpp new file mode 100644 index 0000000..54955b0 --- /dev/null +++ b/Frostbite2D/src/frostbite2D/base/RefObject.cpp @@ -0,0 +1,24 @@ +#include + +namespace frostbite2D { + +RefObject::RefObject() : ref_count_(0) {} + +RefObject::~RefObject() {} + +void RefObject::Retain() { + ++ref_count_; +} + +void RefObject::Release() { + --ref_count_; + if (ref_count_ == 0) { + delete this; + } +} + +uint32_t RefObject::GetRefCount() const { + return ref_count_.load(); +} + +} diff --git a/Frostbite2D/src/frostbite2D/graphics/batch.cpp b/Frostbite2D/src/frostbite2D/graphics/batch.cpp index 776b2cc..643b2db 100644 --- a/Frostbite2D/src/frostbite2D/graphics/batch.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/batch.cpp @@ -73,7 +73,7 @@ void Batch::begin() { currentBatch_.indices.clear(); currentBatch_.key = {0, 0, 0}; currentBatch_.shader = nullptr; - currentBatch_.texture.reset(); + currentBatch_.texture.Reset(); } void Batch::end() { @@ -169,12 +169,12 @@ void Batch::flushCurrentBatch() { glDrawElements(GL_TRIANGLES, static_cast(currentBatch_.indices.size()), - GL_UNSIGNED_SHORT, 0); + GL_UNSIGNED_SHORT, 0); currentBatch_.vertices.clear(); currentBatch_.indices.clear(); currentBatch_.shader = nullptr; - currentBatch_.texture.reset(); + currentBatch_.texture.Reset(); } } diff --git a/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp b/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp index 941b97d..272f46e 100644 --- a/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp @@ -38,7 +38,7 @@ void ShaderManager::shutdown() { Shader* ShaderManager::getShader(const std::string& name) { auto it = shaders_.find(name); if (it != shaders_.end()) { - return it->second.get(); + return it->second.Get(); } SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Shader not found: %s", name.c_str()); return nullptr;