C++实现非C++11版unique_ptr时如何区分指针由new还是new[]分配
首先明确一个核心结论:不存在可移植的标准方法能够仅通过一个裸指针的值判断它是通过new还是new[]分配的。C++标准没有规定裸指针需要携带分配方式相关的元信息,不同编译器的堆内存布局实现属于未公开的私有细节,依赖这类细节的实现不具备可移植性,也不符合学校作业的规范要求。
你可以通过以下两种符合C03标准的方案解决这个问题,不需要用到C11的default_delete特性:
方案1:模板偏特化(推荐,和标准库实现逻辑一致)
标准库本身的unique_ptr就没有尝试从指针判断分配方式,而是通过两个不同的模板特化来区分单对象和数组场景,这个逻辑完全可以在C++03下实现:
- 主模板处理单个对象分配场景,析构调用
delete
template <typename T> class unique_ptr { private: T* ptr_; // C++03下禁止拷贝语义,将拷贝构造和拷贝赋值声明为私有不实现 unique_ptr(const unique_ptr&); unique_ptr& operator=(const unique_ptr&); public: explicit unique_ptr(T* p = 0) : ptr_(p) {} ~unique_ptr() { delete ptr_; } // 其他必要接口实现 T* release() { T* tmp = ptr_; ptr_ = 0; return tmp; } void reset(T* p = 0) { if (ptr_ != p) { delete ptr_; ptr_ = p; } } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } };
- 偏特化版本处理数组分配场景,析构调用
delete[]
template <typename T> class unique_ptr<T[]> { private: T* ptr_; unique_ptr(const unique_ptr&); unique_ptr& operator=(const unique_ptr&); public: explicit unique_ptr(T* p = 0) : ptr_(p) {} ~unique_ptr() { delete[] ptr_; } // 数组版本额外提供下标访问重载 T& operator[](size_t idx) const { return ptr_[idx]; } // 其他通用接口实现 T* release() { T* tmp = ptr_; ptr_ = 0; return tmp; } void reset(T* p = 0) { if (ptr_ != p) { delete[] ptr_; ptr_ = p; } } };
使用时通过显式指定模板参数区分场景即可:
- 单对象分配:
unique_ptr<int> ptr(new int(5)); - 数组分配:
unique_ptr<int[]> ptr(new int[10]);
你示例中unique_ptr<int> ptr(new int[10]);本身就是错误用法,哪怕是标准库的unique_ptr这么写也会触发未定义行为,这类问题属于用户使用错误,不需要你的实现兜底。
方案2:构造时传入分配类型标记
如果你的需求必须让同一个模板实例同时支持两种分配方式,可以在构造函数中新增一个标记参数,由调用方手动指定分配类型:
enum AllocType { SINGLE_ALLOC, // 对应new分配 ARRAY_ALLOC // 对应new[]分配 }; template <typename T> class unique_ptr { private: T* ptr_; AllocType alloc_type_; unique_ptr(const unique_ptr&); unique_ptr& operator=(const unique_ptr&); public: unique_ptr(T* p, AllocType type = SINGLE_ALLOC) : ptr_(p), alloc_type_(type) {} ~unique_ptr() { if (alloc_type_ == SINGLE_ALLOC) { delete ptr_; } else { delete[] ptr_; } } // 其他接口实现省略 };
这种方案的缺点是依赖调用方手动传入正确的标记,出错概率比模板特化方案高,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者Fayeure
相关产品推荐
相关产品推荐

