面向按需分配指针的继承层级转换合规高性能方案咨询
符合标准且高性能的继承类指针转换实现方案
针对你的资产管理库中LazyPtr/FirmPtr的继承类型转换需求,下面提供一套兼顾标准合规性、高性能与类型安全的实现方案,核心思路是通过类型擦除+编译时偏移计算/运行时多态转换重构ReferenceCounter体系,解决模板绑定导致的类型兼容性问题。
核心重构思路
- 将
ReferenceCounter拆分为非模板基类+模板派生类,实现类型擦除,让不同Asset类型的计数器能通过基类指针统一管理。 - 针对非虚拟无歧义继承,利用编译时偏移计算实现零开销转换;针对多态/虚拟继承,用标准
dynamic_cast保证安全转换。 - 扩展LazyPtr/FirmPtr的转换构造函数,通过ReferenceCounter提供的接口完成类型校验与指针转换。
完整代码实现
1. 重构ReferenceCounter体系
#include <typeindex> #include <type_traits> #include <stdexcept> // Asset概念约束,可根据你的需求扩展 template<typename T> concept AssetLike = std::is_class_v<T>; // 非模板基类:提供通用计数逻辑与类型转换接口 class ReferenceCounterBase { protected: std::size_t m_strongcount = 0; std::size_t m_weakcount = 0; virtual void* get_raw_asset() = 0; virtual std::type_index get_asset_type() const = 0; public: virtual ~ReferenceCounterBase() = default; // 弱引用操作 void weak_hold() { ++m_weakcount; } void weak_release() { if (--m_weakcount == 0 && m_strongcount == 0) { forget_impl(); delete this; } } // 强引用操作 void release() { if (--m_strongcount == 0) { allow_unload_impl(); } weak_release(); } // 类型安全的资产指针获取接口 template<AssetLike T> T* get_as() { if constexpr (std::is_polymorphic_v<T>) { // 多态类型:用dynamic_cast保证安全转换 return dynamic_cast<T*>(get_raw_asset()); } else { // 非多态类型:编译时校验继承关系+计算偏移 if (get_asset_type() == std::type_index(typeid(T))) { return static_cast<T*>(get_raw_asset()); } else if constexpr (std::is_base_of_v<T, std::decay_t<decltype(*get_raw_asset())>>) { static_assert(!std::is_virtual_base_of_v<T, std::decay_t<decltype(*get_raw_asset())>>, "Virtual inheritance not supported for non-polymorphic assets"); static_assert(std::is_standard_layout_v<std::decay_t<decltype(*get_raw_asset())>>, "Non-standard layout types cannot use offset-based conversion"); // 编译时计算基类偏移,运行时直接指针加减 return reinterpret_cast<T*>( reinterpret_cast<char*>(get_raw_asset()) + reinterpret_cast<ptrdiff_t>(static_cast<T*>(static_cast<std::decay_t<decltype(*get_raw_asset())>*>(nullptr))) ); } return nullptr; } } // 纯虚方法:委托具体加载/卸载逻辑 virtual void ensure_loaded_impl() = 0; virtual void allow_unload_impl() = 0; virtual void forget_impl() = 0; }; // 模板派生类:绑定具体Asset类型,实现资产存储 template<AssetLike Asset> class ReferenceCounter : public ReferenceCounterBase { protected: Asset* p_asset = nullptr; void* get_raw_asset() override { return p_asset; } std::type_index get_asset_type() const override { return std::type_index(typeid(Asset)); } public: // 获取强引用资产(确保加载) Asset& hold() { ensure_loaded_impl(); ++m_strongcount; return *p_asset; } // 继承基类纯虚方法的具体实现(由AssetManager完成) void ensure_loaded_impl() override; void allow_unload_impl() override; void forget_impl() override; };
2. 修改LazyPtr:支持跨类型转换
template<AssetLike Asset> class LazyPtr { using DecAsset = std::decay_t<Asset>; ReferenceCounterBase* m_p_ctr = nullptr; friend class FirmPtr<DecAsset>; public: LazyPtr() = default; LazyPtr(ReferenceCounter<DecAsset>& ctr) : m_p_ctr(&ctr) { ctr.weak_hold(); } // 同类型拷贝/移动 LazyPtr(const LazyPtr& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) m_p_ctr->weak_hold(); } LazyPtr(LazyPtr&& other) noexcept : m_p_ctr(other.m_p_ctr) { other.m_p_ctr = nullptr; } LazyPtr& operator=(const LazyPtr& other) { if (this != &other) { if (m_p_ctr) m_p_ctr->weak_release(); m_p_ctr = other.m_p_ctr; if (m_p_ctr) m_p_ctr->weak_hold(); } return *this; } LazyPtr& operator=(LazyPtr&& other) noexcept { if (this != &other) { if (m_p_ctr) m_p_ctr->weak_release(); m_p_ctr = other.m_p_ctr; other.m_p_ctr = nullptr; } return *this; } // 跨类型转换构造函数:支持基类<->派生类转换 template<AssetLike OtherAsset> requires (std::is_base_of_v<DecAsset, std::decay_t<OtherAsset>> || std::is_base_of_v<std::decay_t<OtherAsset>, DecAsset>) LazyPtr(const LazyPtr<OtherAsset>& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) { // 运行时校验类型兼容性 if (!m_p_ctr->get_as<DecAsset>()) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->weak_hold(); } } // 从FirmPtr转换 template<AssetLike OtherAsset> requires (std::is_base_of_v<DecAsset, std::decay_t<OtherAsset>> || std::is_base_of_v<std::decay_t<OtherAsset>, DecAsset>) LazyPtr(const FirmPtr<OtherAsset>& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) { if (!m_p_ctr->get_as<DecAsset>()) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->weak_hold(); } } ~LazyPtr() { if (m_p_ctr) m_p_ctr->weak_release(); } };
3. 修改FirmPtr:支持跨类型转换
template<AssetLike Asset> class FirmPtr { using DecAsset = std::decay_t<Asset>; ReferenceCounterBase* m_p_ctr = nullptr; DecAsset* m_p_asset = nullptr; friend class LazyPtr<DecAsset>; public: FirmPtr() = default; FirmPtr(ReferenceCounter<DecAsset>& ctr) : m_p_ctr(&ctr) { m_p_asset = &ctr.hold(); } // 同类型拷贝/移动 FirmPtr(const FirmPtr& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) { m_p_asset = m_p_ctr->get_as<DecAsset>(); if (!m_p_asset) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->hold(); // 增加强引用计数 } } FirmPtr(FirmPtr&& other) noexcept : m_p_ctr(other.m_p_ctr), m_p_asset(other.m_p_asset) { other.m_p_ctr = nullptr; other.m_p_asset = nullptr; } FirmPtr& operator=(const FirmPtr& other) { if (this != &other) { if (m_p_ctr) m_p_ctr->release(); m_p_ctr = other.m_p_ctr; if (m_p_ctr) { m_p_asset = m_p_ctr->get_as<DecAsset>(); if (!m_p_asset) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->hold(); } } return *this; } FirmPtr& operator=(FirmPtr&& other) noexcept { if (this != &other) { if (m_p_ctr) m_p_ctr->release(); m_p_ctr = other.m_p_ctr; m_p_asset = other.m_p_asset; other.m_p_ctr = nullptr; other.m_p_asset = nullptr; } return *this; } // 跨类型转换构造函数 template<AssetLike OtherAsset> requires (std::is_base_of_v<DecAsset, std::decay_t<OtherAsset>> || std::is_base_of_v<std::decay_t<OtherAsset>, DecAsset>) FirmPtr(const FirmPtr<OtherAsset>& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) { m_p_asset = m_p_ctr->get_as<DecAsset>(); if (!m_p_asset) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->hold(); } } // 从LazyPtr转换 FirmPtr(const LazyPtr<DecAsset>& other) : m_p_ctr(other.m_p_ctr) { if (m_p_ctr) { m_p_asset = m_p_ctr->get_as<DecAsset>(); if (!m_p_asset) { m_p_ctr = nullptr; throw std::bad_cast(); } m_p_ctr->hold(); } } ~FirmPtr() { if (m_p_ctr) m_p_ctr->release(); } // 重载指针操作符 DecAsset& operator*() const { return *m_p_asset; } DecAsset* operator->() const { return m_p_asset; } };
方案优势
- 标准合规性:
- 非多态类型转换使用
offsetof等价的编译时偏移计算,符合C++标准对标准布局类型的要求。 - 多态类型转换依赖
dynamic_cast,是标准中唯一安全的跨虚拟继承转换方式。
- 非多态类型转换使用
- 高性能:
- 非多态类型转换完全在编译时完成,运行时仅需一次指针加减操作,无额外开销。
- 多态类型转换仅在构造/转换时执行一次
dynamic_cast,后续访问直接使用缓存的指针,性能损失可忽略。
- 类型安全:
- 编译时通过
concept和static_assert校验继承关系与类型布局。 - 运行时通过类型索引和
dynamic_cast确保转换合法性,避免未定义行为。
- 编译时通过
内容的提问来源于stack exchange,提问作者LMauricius
相关产品推荐
相关产品推荐

