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

自定义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,导致原栈对象和函数内的临时栈对象共享同一块堆内存:

  1. 函数执行完毕后,临时对象销毁时调用析构函数delete[] data,释放共享内存
  2. 后续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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:31:15