C++动态栈new/delete实现 Valgrind内存泄漏delete放置位置问题
问题根因
- 扩容时内存泄漏:你在push方法扩容时,只申请了新的内存块,没有释放
data原来指向的旧内存块,直接修改data指向新地址后,旧内存的地址丢失,无法再被回收,就会触发valgrind的泄漏报警。 - 冗余的
ptr成员变量:ptr仅在扩容逻辑中作为临时指针使用,完全不需要定义为类的成员变量。你把它设为成员后,扩容完成时ptr和data指向同一块内存,此时如果在析构中同时释放ptr和data,就是对同一块内存执行两次delete,自然会报double free错误。 - 额外问题:你的类声明了
clear方法但没有实现,同时没有遵循「三法则」(如果自定义了析构函数,就需要同时自定义拷贝构造函数和拷贝赋值运算符),默认生成的浅拷贝逻辑会导致两个栈对象共享同一块堆内存,析构时也会触发重复释放问题。
修复代码
stack.h
class stack { public: void push(int a); int pop(); void clear(); stack(); // 新增拷贝构造 stack(const stack& other); // 新增拷贝赋值运算符 stack& operator=(stack other); ~stack(); private: int top; int size; int *data; // 删掉冗余的ptr成员 };
stack.cpp
#include <assert.h> #include <stdlib.h> #include <stdio.h> #include "stack.h" #include <algorithm> #define INITIAL_STACKSIZE 1 stack::stack() { top = 0; size = INITIAL_STACKSIZE; data = new int[size]; } // 拷贝构造实现 stack::stack(const stack& other) { top = other.top; size = other.size; data = new int[size]; std::copy(other.data, other.data + top, data); } // 拷贝赋值实现(copy-and-swap写法,避免自赋值问题) stack& stack::operator=(stack other) { std::swap(top, other.top); std::swap(size, other.size); std::swap(data, other.data); return *this; } stack::~stack() { delete [] data; } void stack::push(int a) { if(top >= size) { int new_size = size * 2; // ptr改为局部变量,不需要作为成员 int* ptr = new int[new_size]; std::copy(data, data + top, ptr); // 释放旧的内存块,避免泄漏 delete [] data; data = ptr; size = new_size; } data[top++]=a; } int stack::pop() { assert(top>0); return data[--top]; } // 补上clear方法的实现 void stack::clear() { delete [] data; top = 0; size = INITIAL_STACKSIZE; data = new int[size]; }
teststack.cpp 无需修改
修改后重新编译运行,再用valgrind --leak-check=full检测就不会出现内存泄漏和double free的报错了。
内容的提问来源于stack exchange,提问作者Nate Morning
相关产品推荐
相关产品推荐

