自定义stackm类调用equal_stacks时触发RtlValidateHeap堆错误排查
自定义栈类判断相等时触发堆错误:Invalid address specified to RtlValidateHeap
运行程序时出现如下错误:
HEAP[ldf.exe]: Invalid address specified to RtlValidateHeap
我编写了一个用自定义stackm模板类实现栈功能、判断两个栈是否相等的程序。程序在equal_stacks函数返回结果前均能正常运行,但结束时触发上述堆错误。怀疑问题与传入函数的栈对象销毁有关,析构函数由老师编写确认正确,猜测错误出在equal_stacks函数中。以下是完整代码:
#include <iostream> template<typename T> class stackm{ int capacity; int count; T* data; public: stackm(); ~stackm(); void push(const T& elem); void push(T&& elem); void pop(); T& top(); const T& top() const; int size() const; }; template<typename T> stackm<T>::stackm() { capacity = 1; count = 0; data = new T[1]; } template<typename T> stackm<T>:: ~stackm() { delete[] data; } template<typename T> void stackm<T>::pop() { --count; } template <typename T> void stackm<T>::push(const T& elem) { if (this->count == this->capacity) { size_t new_capacity = capacity * 2; T* new_data = new T[new_capacity]; for (size_t i = 0; i < this->capacity; ++i) { new_data[i] = std::move(this->data[i]); } delete[] this->data; this->capacity = new_capacity; this->data = new_data; } data[count++] = elem; } template <typename T> void stackm<T>::push(T&& elem) { if (this->count == this->capacity) { size_t new_capacity = capacity * 2; T* new_data = new T[new_capacity]; for (size_t i = 0; i < this->capacity; ++i) { new_data[i] = std::move(this->data[i]); } delete[] this->data; this->capacity = new_capacity; this->data = new_data; } data[count++] = elem; } template <typename T> int stackm<T>::size() const { return count; } template <typename T> T& stackm<T>::top() { return data[count - 1]; } template <typename T> const T& stackm<T>::top() const { return data[count - 1]; } template<typename Stack> bool equal_stacks(Stack s1, Stack s2) { if (s1.size() != s2.size()) { return false; } while (s1.size() != 0) { if (s2.top() != s1.top()) { return false; } s1.pop(); s2.pop(); } return true; } int main() { stackm<int> stac1 = stackm<int>(); stackm<int> sd23 = stackm<int>(); sd23.push(23); sd23.push(45); std::cout << equal_stacks<stackm<int>>(stac1, sd23); }
问题根源
stackm类未定义拷贝构造函数和拷贝赋值运算符,当equal_stacks以值传递方式接收参数时,编译器自动生成的默认拷贝构造函数仅做浅拷贝——直接复制指针data,导致原栈对象和函数内的临时栈对象共享同一块堆内存:
- 函数执行完毕后,临时对象销毁时调用析构函数
delete[] data,释放共享内存 - 后续
main函数中的原栈对象销毁时,会再次释放已被释放的内存,触发堆重复释放错误,即你看到的RtlValidateHeap报错
解决方法
方法1:实现深拷贝的拷贝构造与赋值运算符
为stackm类添加深拷贝逻辑,确保每个栈对象拥有独立的堆内存:
template<typename T> stackm<T>::stackm(const stackm<T>& other) { capacity = other.capacity; count = other.count; data = new T[capacity]; // 逐元素复制 for (int i = 0; i < count; ++i) { data[i] = other.data[i]; } } template<typename T> stackm<T>& stackm<T>::operator=(const stackm<T>& other) { if (this != &other) { // 避免自赋值 delete[] data; // 释放当前内存 capacity = other.capacity; count = other.count; data = new T[capacity]; for (int i = 0; i < count; ++i) { data[i] = other.data[i]; } } return *this; }
方法2:修改函数为const引用传递
如果不需要修改原栈对象,用const引用传递参数避免临时拷贝,同时在函数内创建临时栈进行操作:
template<typename Stack> bool equal_stacks(const Stack& s1, const Stack& s2) { if (s1.size() != s2.size()) { return false; } // 创建临时栈操作,不修改原对象 Stack temp1 = s1; Stack temp2 = s2; while (temp1.size() != 0) { if (temp2.top() != temp1.top()) { return false; } temp1.pop(); temp2.pop(); } return true; }
额外优化建议
- 将
push函数中的扩容逻辑提取为私有成员函数,减少代码冗余 - 可补充移动构造和移动赋值运算符,提升对象转移时的性能
内容的提问来源于stack exchange,提问作者Catnip
相关产品推荐
相关产品推荐

