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

C++实现自定义std::shared_ptr如何编译期选择适配数组的特殊删除器

问题原因

你遇到的报错核心是内存释放逻辑不匹配:

  • new T[10] 分配的数组需要调用 delete[] 释放,会逐个析构数组内所有元素,再释放整块内存
  • 你当前的默认删除器是 std::default_delete<Type>,内部调用的是 delete,只会析构第一个元素,且和 new[] 的内存分配逻辑不匹配,因此触发malloc释放错误

你之前写的std::conditional不生效的原因是判断条件错误:std::is_array_v<t_SharedPTR> 检查的是SharedPTR类本身是不是数组类型,结果永远为假,永远不会选到数组版本的删除器。


修正方案

和标准库std::shared_ptr的实现逻辑对齐,做两处核心修改:

1. 调整默认删除器的自动选择逻辑

将模板参数的默认删除器改为根据Type是否为数组类型自动选择,同时引入需要的头文件:

#include <type_traits>
#include <cstddef>
#include <functional>

// 主模板:普通非数组类型
template<typename Type, class TDeleter = std::conditional_t<
    std::is_array_v<Type>,
    std::default_delete<Type>,
    std::default_delete<Type>
>>
class SharedPTR final {
    using t_SharedPTR = SharedPTR<Type, TDeleter>;
    using ptr_type = Type*;
    using deleter_type = TDeleter;
    // 删除原来成员变量处的std::conditional初始化逻辑,直接使用默认构造即可
    deleter_type deleter;
    ptr_type data = nullptr;
    long* count = nullptr;

    // ... 其余原有成员逻辑保持不变
};

2. 增加数组类型的偏特化

专门处理SharedPTR<T[]>的数组使用场景,同时增加数组下标访问运算符:

// 数组类型偏特化
template<typename Type, class TDeleter>
class SharedPTR<Type[], TDeleter> final {
    using t_SharedPTR = SharedPTR<Type[], TDeleter>;
    using ptr_type = Type*;
    using deleter_type = TDeleter;
    deleter_type deleter;
    ptr_type data = nullptr;
    long* count = nullptr;

    void increment_count(){
        if(data != nullptr){
            (*count)++;
        }
    };
public:
    SharedPTR() = default;
    SharedPTR(std::nullptr_t) : data(nullptr), count(nullptr){};
    explicit SharedPTR(ptr_type ptr){
        data = ptr;
        count = new long(0);
        increment_count();
    };
    // 拷贝、移动、赋值、析构逻辑和主模板完全一致
    SharedPTR(const t_SharedPTR& other) : data(other.data), count(other.count){
        increment_count();
    };
    SharedPTR(t_SharedPTR&& other) noexcept : data(other.data), count(other.count), deleter(other.deleter){
        other.data = nullptr;
        other.count = nullptr;
    };
    ~SharedPTR(){
        release();
    };

    t_SharedPTR& operator=(t_SharedPTR&& other) noexcept{
        release();
        data = other.data;
        count = other.count;
        deleter = other.deleter;
        other.data = nullptr;
        other.count = nullptr;
        return *this;
    };
    t_SharedPTR& operator=(Type* ptr){
        release();
        data = ptr;
        if(data != nullptr){
            count = new long(0);
            increment_count();
        }
        return *this;
    };
    t_SharedPTR& operator=(const t_SharedPTR& other){
        release();
        data = other.data;
        count = other.count;
        deleter = other.deleter;
        increment_count();
        return *this;
    };

    // 新增数组下标访问
    Type& operator[](size_t idx) const {
        return data[idx];
    }

    // 其余成员函数(get、use_count、release、reset等)和主模板保持一致即可
    Type* get() const {
        return data;
    };
    operator bool() const{
        return get() != nullptr;
    };
    long use_count() const {
        return count ? *count : 0;
    }
    bool unique() const {
        return use_count() == 1;
    }
    void release(){
        if(count != nullptr){
            if(*count == 1){
                deleter(data);
                delete count;
            }
            else {
                (*count)--;
            }
        };
    };
    void reset(ptr_type ptr = nullptr){
        release();
        data = ptr;
        count = new long(0);
        increment_count();
    };
    void swap(t_SharedPTR& sharedPTR){
        std::swap(data, sharedPTR.data);
        std::swap(count, sharedPTR.count);
    };
};

使用方式

和标准库std::shared_ptr保持一致,存储数组时显式声明数组类型:

int main() {
    SharedPTR<T[]> a(new T[10]); // 显式指定T[]类型,自动匹配数组版本删除器
    return 0;
}

运行后会正确打印10次~T(),不会出现内存释放错误。

如果想要避免用户误将数组指针传入非数组类型的SharedPTR<T>,可以在主模板的构造函数中加入静态断言实现编译期报错:

explicit SharedPTR(ptr_type ptr){
    static_assert(!std::is_array_v<Type>, "数组类型请使用SharedPTR<T[]>声明");
    data = ptr;
    count = new long(0);
    increment_count();
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:15:04