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

C++自定义Array类popback()无法正确删除末尾元素问题

问题分析与修复方案

核心问题:越界访问的未定义行为

你的popback()函数其实已经正确完成了数组有效长度的缩减(size变为3),但你在main()里错误地访问了index=3、4、6这些超出当前数组有效范围的位置——这些内存要么已经被释放,要么从来不属于当前数组的有效区域,读取到的值是随机的(你看到的7只是原内存未被系统覆盖的巧合),这属于C++中的未定义行为,和delete[]是否完全释放内存无关。

代码中的冗余与风险点

  • pushback/popback存在冗余内存操作:创建临时数组后,又重新分配了一次arry再复制数据,完全可以直接让arry指向临时数组,避免不必要的内存开销。
  • 未处理边界情况:当数组size为0时调用popback(),会执行new int[-1],直接触发运行时错误。
  • access函数无边界检查:越界访问不会有任何提示,容易隐藏问题。
  • 缺少析构函数:对象销毁时不会释放arry指向的内存,会造成内存泄漏。

修复后的完整代码

#include <iostream>
#include <stdexcept>

using namespace std;

class Array{
private:
    int *arry;
    int sizeofarray;
public:
    Array() : sizeofarray(0), arry(new int[0]) {}
    
    // 析构函数:防止内存泄漏
    ~Array() {
        delete[] arry;
    }

    // 拷贝构造与赋值运算符(Rule of Three),避免浅拷贝问题
    Array(const Array& other) : sizeofarray(other.sizeofarray), arry(new int[other.sizeofarray]) {
        for(int i = 0; i < sizeofarray; ++i) {
            arry[i] = other.arry[i];
        }
    }

    Array& operator=(const Array& other) {
        if(this != &other) {
            delete[] arry;
            sizeofarray = other.sizeofarray;
            arry = new int[sizeofarray];
            for(int i = 0; i < sizeofarray; ++i) {
                arry[i] = other.arry[i];
            }
        }
        return *this;
    }

    int access(int index) {
        // 添加边界检查,越界抛出异常
        if(index < 0 || index >= sizeofarray) {
            throw out_of_range("Array index out of bounds");
        }
        return arry[index];
    }

    void pushback(int element) {
        int *temparray = new int[sizeofarray + 1];
        for(int i = 0; i < sizeofarray; ++i) {
            temparray[i] = arry[i];
        }
        temparray[sizeofarray] = element;
        delete[] arry;
        arry = temparray; // 直接指向临时数组,无需重新分配
        sizeofarray++;
    }

    void popback() {
        // 处理空数组的边界情况
        if(sizeofarray == 0) {
            throw underflow_error("Cannot pop from empty array");
        }
        int *temparray = new int[sizeofarray - 1];
        for(int i = 0; i < sizeofarray - 1; ++i) {
            temparray[i] = arry[i];
        }
        delete[] arry;
        arry = temparray; // 直接指向临时数组
        sizeofarray--;
    }

    int sizey() {
        return sizeofarray;
    }
};

int main(){
    Array myfirstvector;

    myfirstvector.pushback(9);
    myfirstvector.pushback(2);
    myfirstvector.pushback(3);
    myfirstvector.pushback(4);
    myfirstvector.pushback(7);
    myfirstvector.popback();
    myfirstvector.popback();

    // 仅访问有效范围内的元素(0到size-1)
    cout << myfirstvector.access(0) << " " << myfirstvector.access(1) << " " << myfirstvector.access(2) << endl;
    cout << "Size of array: " << myfirstvector.sizey() << endl;

    return 0;
}

关键修改说明

  1. 成员变量私有化:避免外部直接修改arry和sizeofarray,保证封装性。
  2. 添加析构函数与Rule of Three:防止内存泄漏,避免浅拷贝导致的重复释放问题。
  3. 简化pushback/popback逻辑:直接让arry指向临时数组,去掉冗余的内存分配操作。
  4. 边界检查:在access和popback中添加边界判断,越界时抛出异常,便于调试定位问题。
  5. 修正main函数访问范围:只访问有效索引(0到size-1),符合vector的使用逻辑——pop_back后,原末尾元素的位置不再属于数组有效范围,不应再访问。

关于vector的pop_back()逻辑对齐

std::vector的pop_back()仅将内部size减一,不会主动释放内存(也不会修改原末尾元素的值),但访问超出size的元素同样是未定义行为。如果想完全对齐vector的逻辑,可以额外维护capacity(容量)变量,只有当size远小于capacity时才缩减内存,不过当前你的实现(每次popback都缩小内存)也是一种合理的设计。

内容的提问来源于stack exchange,提问作者Harinandan N

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:27:10