动态数组无法添加新元素,expand()方法异常求助
问题分析与解决方案
错误原因
你遇到的类型转换错误本质是模板实例化后的类型不匹配:
当T为obj*时:
new T(*this->myArray[i])等价于new obj*(*myArray[i])——这里*myArray[i]是obj对象,而obj*无法直接用obj对象初始化,因此报“cannot convert from 'obj' to 'T'”。new T(...)返回的是T*(即obj**),但tempArr[i]的类型是T(即obj*),指针层级不匹配,因此报“cannot convert from 'T*' to 'T'”。
而浅拷贝的问题在于,当存储指针类型时,拷贝的只是指针地址,原数组释放后,临时数组的指针指向已失效的内存空间。
解决方案
方案1:模板特化(针对特定指针类型)
如果你的动态数组只需要处理obj*这类特定指针类型,可以为dynamicArray编写模板特化版本,直接实现指针的深拷贝逻辑:
#include <cstddef> // 原模板类(处理非指针类型) template<typename T> class dynamicArray { protected: T* myArray; size_t size; size_t capacity; public: // 构造、析构、add等基础方法... void expand() { size_t newCapacity = capacity * 2; T* tempArr = new T[newCapacity]; for (size_t i = 0; i < size; ++i) { tempArr[i] = myArray[i]; // 非指针类型直接拷贝 } delete[] myArray; myArray = tempArr; capacity = newCapacity; } }; // 针对obj*的特化版本 template<> class dynamicArray<obj*> { private: obj** myArray; size_t size; size_t capacity; public: dynamicArray() : size(0), capacity(4) { myArray = new obj*[capacity]; } ~dynamicArray() { // 先释放每个指针指向的对象 for (size_t i = 0; i < size; ++i) { delete myArray[i]; } delete[] myArray; } void add(obj* elem) { if (size >= capacity) { expand(); } myArray[size++] = new obj(*elem); // 存储前先深拷贝对象 } void expand() { size_t newCapacity = capacity * 2; obj** tempArr = new obj*[newCapacity]; for (size_t i = 0; i < size; ++i) { tempArr[i] = new obj(*myArray[i]); // 深拷贝每个obj对象 } // 释放原数组资源 for (size_t i = 0; i < size; ++i) { delete myArray[i]; } delete[] myArray; myArray = tempArr; capacity = newCapacity; } };
方案2:通用类型萃取(支持任意指针类型)
如果需要让模板支持任意指针类型的深拷贝,可以用C++标准库的类型萃取工具std::is_pointer_v和std::remove_pointer_t,在模板中做分支处理:
#include <cstddef> #include <type_traits> template<typename T> class dynamicArray { private: T* myArray; size_t size; size_t capacity; // 辅助函数:处理指针类型的拷贝 template<typename U = T> std::enable_if_t<std::is_pointer_v<U>, void> copyElement(U& dest, const U& src) { using ValueType = std::remove_pointer_t<U>; dest = new ValueType(*src); // 深拷贝指针指向的对象 } // 辅助函数:处理非指针类型的拷贝 template<typename U = T> std::enable_if_t<!std::is_pointer_v<U>, void> copyElement(U& dest, const U& src) { dest = src; // 直接拷贝构造 } // 辅助函数:释放指针类型资源 template<typename U = T> std::enable_if_t<std::is_pointer_v<U>, void> releaseElement(U elem) { delete elem; } // 辅助函数:释放非指针类型资源(空操作) template<typename U = T> std::enable_if_t<!std::is_pointer_v<U>, void> releaseElement(U) {} public: dynamicArray() : size(0), capacity(4) { myArray = new T[capacity]; } ~dynamicArray() { for (size_t i = 0; i < size; ++i) { releaseElement(myArray[i]); } delete[] myArray; } void add(const T& elem) { if (size >= capacity) { expand(); } copyElement(myArray[size], elem); size++; } void expand() { size_t newCapacity = capacity * 2; T* tempArr = new T[newCapacity]; for (size_t i = 0; i < size; ++i) { copyElement(tempArr[i], myArray[i]); } // 释放原数组资源 for (size_t i = 0; i < size; ++i) { releaseElement(myArray[i]); } delete[] myArray; myArray = tempArr; capacity = newCapacity; } };
这个方案会自动识别T是否为指针类型:
- 若是指针,会深拷贝指向的对象;
- 若不是,则直接执行普通拷贝。
方案3:调整设计——存储对象而非指针
如果业务场景允许,直接存储obj对象而非obj*,可以彻底避免指针管理的问题。只要obj类实现了正确的拷贝构造函数,模板的默认拷贝逻辑就能完成深拷贝:
// 确保obj类有正确的拷贝构造 class obj { private: int* data; public: obj(int val) : data(new int(val)) {} // 深拷贝构造函数 obj(const obj& other) : data(new int(*other.data)) {} // 重载赋值运算符 obj& operator=(const obj& other) { if (this != &other) { delete data; data = new int(*other.data); } return *this; } ~obj() { delete data; } }; // 使用dynamicArray<obj>而非dynamicArray<obj*> dynamicArray<obj> arr; arr.add(obj(10)); arr.add(obj(20));
内容的提问来源于stack exchange,提问作者xzysiek
相关产品推荐
相关产品推荐

