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

C++自定义栈类实现触发std::logic_error异常的问题求助

修复你的C++栈实现中的指针错误与内存异常问题

嘿,第一次尝试用C++实现栈已经很棒了!咱们直接看问题出在哪:

你的核心问题出在myStackElement::popped函数的参数传递上——这个函数里的head是传值参数,你在函数内部修改head = prev,只会改变局部变量的值,完全不会影响myStack类里的成员变量head。这就导致执行pop之后,myStack的head仍然指向已经被delete的节点,变成了野指针。后续调用peek时,你访问的是已经释放的内存里的Data成员,这就触发了字符串构造的异常(也就是你看到的std::logic_error)。

一步步修正你的代码

我们把栈的管理逻辑还给myStack类,让myStackElement只负责存储数据和关联关系,这样逻辑更清晰,也能避免指针混乱:

#include <iostream>
#include <string>
// 建议不要用using namespace std,避免命名冲突
// using namespace std;

class myStackElement {
private:
    std::string Data;
    myStackElement* prev;
public:
    // 用初始化列表代替构造函数内赋值,更高效
    myStackElement(std::string myData, myStackElement* head) 
        : Data(std::move(myData)), prev(head) {}

    // 只提供获取数据和前一个节点的接口
    std::string getValue() const {
        return Data;
    }

    myStackElement* getPrev() const {
        return prev;
    }
};

class myStack {
private:
    myStackElement* head;
public:
    // 用nullptr代替NULL,类型更安全
    myStack() : head(nullptr) {}

    void push(std::string myData) {
        myStackElement* temp = new myStackElement(std::move(myData), head);
        head = temp;
    }

    std::string pop() {
        if (head == nullptr) {
            // 返回空字符串比"0"更合理,也可以选择抛出异常
            return "";
        } else {
            myStackElement* temp = head;
            std::string poppedValue = temp->getValue();
            // 直接在myStack里更新head指针,这才是正确的操作!
            head = temp->getPrev();
            delete temp; // 现在删除的是旧节点,head已经指向新的栈顶了
            return poppedValue;
        }
    }

    std::string peek() {
        if (head == nullptr) {
            return "";
        } else {
            return head->getValue();
        }
    }

    // 必须添加析构函数,避免内存泄漏
    ~myStack() {
        while (head != nullptr) {
            myStackElement* temp = head;
            head = head->getPrev();
            delete temp;
        }
    }
};

int main() {
    myStack hello;
    hello.push("other");
    std::string top = hello.peek();
    std::cout << top << std::endl;
    hello.push("another");
    top = hello.peek();
    std::cout << top << std::endl;
    std::string popped = hello.pop();
    std::cout << popped << std::endl;
    top = hello.peek();
    std::cout << top << std::endl;
    return 0;
}

关键修改点说明

  1. 修正指针更新逻辑:把栈顶指针的更新逻辑移到myStack::pop函数里,直接通过temp->getPrev()获取前一个节点,再更新head,这样就不会出现野指针了。
  2. 简化元素类职责:myStackElement只负责存储数据和关联前一个节点,不再干预栈的管理,符合单一职责原则。
  3. 修复内存泄漏:添加了析构函数,遍历整个栈并删除所有节点,避免程序结束后残留未释放的内存。
  4. 现代C++规范优化:用nullptr代替NULL,用初始化列表构造对象,用std::move减少字符串拷贝。

现在运行代码会得到正确的输出:

other
another
another
other

而且不会再触发任何异常。

额外小建议

  • 可以把myStackElement设为myStack的内部类,这样外部代码无法直接访问它,封装性更好。
  • 可以把myStack改成模板类,让它支持存储任意类型的数据(比如int、double),而不只是std::string。

内容的提问来源于stack exchange,提问作者mr.loop

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 00:47:34