如何继承unique_ptr<T[]>全部构造函数?转换错误求解
问题分析与解决方案
错误原因拆解
1. 初始代码类型不匹配
你最初的测试代码里,unique_ptr<byte>是管理单个对象的智能指针,而unique_array_ptr继承自unique_ptr<Tp[], Dp>——管理数组的智能指针,这是两个完全独立的类型,自然无法转换。
2. 更新后代码的构造函数缺失
即使改成unique_ptr<byte[], function<void(byte*)>>,派生类unique_array_ptr<byte>也没有对应的构造函数接收基类的右值。using unique_ptr<Tp[], Dp>::unique_ptr;只会继承基类自身的构造逻辑(比如从裸指针+删除器构造),但不会自动生成「从基类右值构造派生类」的构造函数——基类到派生类的转换需要显式定义。
另外还有一个隐藏bug:你的malloc构造函数里,malloc(size)只分配了size字节,而非size * sizeof(Tp),这会导致数组空间分配不足,后续访问必然触发越界错误。
修正后的代码方案
基础修正版
解决类型匹配问题,添加基类移动构造,修复malloc字节数计算:
#include <memory> #include <functional> using std::function; using std::unique_ptr; using std::byte; // 避免使用标准库保留的下划线大写标识符,改用Tp、Dp template<class Tp, class Dp = function<void(Tp*)>> class unique_array_ptr : public unique_ptr<Tp[], Dp> { public: // 继承基类所有构造函数 using unique_ptr<Tp[], Dp>::unique_ptr; // 新增:从基类右值构造派生类 unique_array_ptr(unique_ptr<Tp[], Dp>&& other) noexcept : unique_ptr<Tp[], Dp>(std::move(other)), size(0) {} // 修复malloc字节数计算的构造函数 unique_array_ptr(const size_t size) : unique_ptr<Tp[], Dp>(static_cast<Tp*>(malloc(size * sizeof(Tp))), free), size(size) {} // 重载构造:从外部unique_ptr移动时手动指定数组大小 unique_array_ptr(unique_ptr<Tp[], Dp>&& other, const size_t size) noexcept : unique_ptr<Tp[], Dp>(std::move(other)), size(size) {} const size_t size; }; // 测试1:从数组版unique_ptr移动 void test_move_from_array_ptr() { unique_ptr<byte[]> hello(new byte[5]); unique_array_ptr<byte> test(std::move(hello), 5); } // 测试2:从带自定义删除器的unique_ptr移动 void test_move_from_custom_deleter() { unique_ptr<byte[], function<void(byte*)>> hello(new byte[5], [](byte* p) { delete[] p; }); unique_array_ptr<byte> test(std::move(hello), 5); } // 测试3:使用malloc构造数组 void test_malloc_constructor() { unique_array_ptr<byte> test(10); // 此时test.size == 10,指向malloc分配的10个byte的数组 }
增强兼容版(支持任意删除器的unique_ptr)
如果需要兼容更多类型的unique_ptr<Tp[]>,可以添加模板构造函数:
template<class Tp, class Dp = function<void(Tp*)>> class unique_array_ptr : public unique_ptr<Tp[], Dp> { public: using unique_ptr<Tp[], Dp>::unique_ptr; // 模板构造:兼容任意可转换的删除器类型 template<typename OtherDp> unique_array_ptr(unique_ptr<Tp[], OtherDp>&& other) noexcept : unique_ptr<Tp[], Dp>(std::move(other)), size(0) {} template<typename OtherDp> unique_array_ptr(unique_ptr<Tp[], OtherDp>&& other, const size_t size) noexcept : unique_ptr<Tp[], Dp>(std::move(other)), size(size) {} unique_array_ptr(const size_t size) : unique_ptr<Tp[], Dp>(static_cast<Tp*>(malloc(size * sizeof(Tp))), free), size(size) {} const size_t size; };
关键注意事项
- 永远不要混用
unique_ptr<T>和unique_ptr<T[]>:前者调用delete,后者调用delete[],类型不兼容会导致未定义行为。 - malloc分配数组时必须计算总字节数:
size * sizeof(Tp),否则空间不足会触发越界错误。 - 从外部
unique_ptr移动到派生类时,派生类无法自动获取数组大小——因为原生unique_ptr<T[]>本身不存储大小,必须手动传入。
内容的提问来源于stack exchange,提问作者Dylan Bradshaw
相关产品推荐
相关产品推荐

