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

C++动态数组Resize异常:结构体嵌套数组数据丢失

问题:自定义Array类reSize后嵌套Array数据丢失,且存在内存泄漏风险

问题描述

我在自定义的Array头文件中实现了reSize函数,主函数中使用嵌套Array结构(User结构体包含Array),调用reSize后User中的data数据丢失。注释掉delete[] 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:45:26