C++动态数组Resize异常:结构体嵌套数组数据丢失
问题描述
我在自定义的Array头文件中实现了reSize函数,主函数中使用嵌套Array结构(User结构体包含Arraydelete[] old后功能恢复正常,但会造成内存泄漏,需要修复该问题。
现有reSize函数实现
void reSize(int newsize) { T* old = items; size = newsize; items = new T[newsize]; for (int i = 0;i < length;i++) items[i] = old[i]; delete[]old; }
主函数代码
struct User{ string name; Array<int> data; }; int main() { Array<User> x(3); x.get(0).name = "Kmal"; x.get(0).data.push_back(2); x.get(0).data.push_back(3); x.reSize(10); cout << x.get(0).data.get(0) <<endl; return 0; }
完整Array类实现
#include <iostream> using namespace std; template <class T> class Array { private : T* items; int size; int length; public : Array() { this->size = 0; items = new T[this->size]; length = 0; } Array(int size) { this->size = size; items = new T[this->size]; length = 0; } int getsize() { return this->size; } template <class T> void push_back(T x) { if ((length+1) <= size) { items[length] = x; length++; } else { this->reSize(size+1); items[length] = x; length++; } } template <class T> void Insert(int index, T x) { if (length + 1 <= size) { for (int i = length;i > index;i--) { items[i] = items[i - 1]; } items[index] = x; length++; } else { this->reSize(size+1); for (int i = length;i > index;i--) { items[i] = items[i - 1]; } items[length] = x; length++; } } template <class T> int Find(T x) { int index = -1; for (int i = 0;i < length;i++) { if (items[i] ==x) { index = i; break; } } return index; } void remove(int index) { items[index] = ""; if(index+1 < length) for (int i = index;i < length-1;i++) { items[i] = items[i + 1]; items[i + 1] = ""; } length--; } void reSize(int newsize) { T* old = items; size = newsize; items = new T[newsize]; for (int i = 0;i < length;i++) items[i] = old[i]; delete[]old; } void Merge(Array<T> x){ T* old = items; int oldlength = length; items = new T[size + x.size]; size = size + x.size; length += x.length; for (int i = 0;i < length;i++) { if(i< oldlength) items[i] = old[i]; else items[i] = x.items[i-oldlength]; } delete[] old; } T& get(int index) { return items[index]; } }
问题原因
核心问题是浅拷贝:
当Array<User>执行reSize时,通过items[i] = old[i]赋值User对象,而User内部的Array<int>没有实现深拷贝逻辑。默认的赋值操作只会拷贝Array<int>的指针、size和length成员,导致新、旧User对象的data指向同一块内存。
执行delete[] old时,旧数组中的User对象被销毁,其内部Array<int>的析构函数会释放data指向的内存,此时新数组中User的data就变成了悬空指针,访问时自然丢失数据。
注释delete[] old后,旧内存未被释放,新对象的data还能访问原内存,但会造成内存泄漏。
修复方案
给Array类实现深拷贝逻辑,包括拷贝构造函数、赋值运算符重载,同时补充析构函数避免内存泄漏,还要修复类中其他泛型兼容问题。
1. 添加析构函数
在Array类的public区域添加:
~Array() { delete[] items; }
2. 添加拷贝构造函数
实现深拷贝,确保新对象拥有独立的内存空间:
Array(const Array<T>& other) { this->size = other.size; this->length = other.length; this->items = new T[this->size]; for (int i = 0; i < this->length; ++i) { this->items[i] = other.items[i]; } }
3. 添加赋值运算符重载
处理自赋值,先释放当前内存再完成深拷贝:
Array<T>& operator=(const Array<T>& other) { if (this == &other) { return *this; // 避免自赋值导致的内存泄漏 } delete[] this->items; this->size = other.size; this->length = other.length; this->items = new T[this->size]; for (int i = 0; i < this->length; ++i) { this->items[i] = other.items[i]; } return *this; }
4. 修复成员函数模板冲突
原push_back、Insert、Find函数内部的template <class T>会覆盖类模板的T,导致编译错误,需去掉内部模板声明:
- 修改push_back:
void push_back(T x) { if ((length+1) <= size) { items[length] = x; length++; } else { this->reSize(size+1); items[length] = x; length++; } }
- 同理修改Insert和Find函数,去掉内部的
template <class T>。
5. 修复remove函数的泛型兼容性
原remove函数中items[index] = ""只适用于字符串,改为泛型兼容的逻辑:
void remove(int index) { if (index < 0 || index >= length) { return; // 处理非法索引 } for (int i = index; i < length - 1; ++i) { items[i] = items[i + 1]; } length--; }
修复完成后,reSize函数无需修改:当执行items[i] = old[i]时,会调用Array的赋值运算符完成深拷贝,新User对象的data拥有独立内存,删除old数组时不会影响新对象的数据,同时避免了内存泄漏。
内容的提问来源于stack exchange,提问作者Lost

