You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

面向按需分配指针的继承层级转换合规高性能方案咨询

符合标准且高性能的继承类指针转换实现方案

针对你的资产管理库中LazyPtr/FirmPtr的继承类型转换需求,下面提供一套兼顾标准合规性、高性能与类型安全的实现方案,核心思路是通过类型擦除+编译时偏移计算/运行时多态转换重构ReferenceCounter体系,解决模板绑定导致的类型兼容性问题。

核心重构思路

  1. 将ReferenceCounter拆分为非模板基类+模板派生类,实现类型擦除,让不同Asset类型的计数器能通过基类指针统一管理。
  2. 针对非虚拟无歧义继承,利用编译时偏移计算实现零开销转换;针对多态/虚拟继承,用标准dynamic_cast保证安全转换。
  3. 扩展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; }
};

方案优势

  1. 标准合规性:
    • 非多态类型转换使用offsetof等价的编译时偏移计算,符合C++标准对标准布局类型的要求。
    • 多态类型转换依赖dynamic_cast,是标准中唯一安全的跨虚拟继承转换方式。
  2. 高性能:
    • 非多态类型转换完全在编译时完成,运行时仅需一次指针加减操作,无额外开销。
    • 多态类型转换仅在构造/转换时执行一次dynamic_cast,后续访问直接使用缓存的指针,性能损失可忽略。
  3. 类型安全:
    • 编译时通过concept和static_assert校验继承关系与类型布局。
    • 运行时通过类型索引和dynamic_cast确保转换合法性,避免未定义行为。

内容的提问来源于stack exchange,提问作者LMauricius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:59:52