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

C++中使用迭代器修改对象时遇到的问题

问题分析与解决方案

嘿,我仔细看了你的代码,问题的根源其实是对象切片加上容器存储方式不对,导致你调用push/pop时根本没操作到真正的Stack/Queue对象,而且你的SimpleList里还有几个逻辑bug,咱们一步步来理清楚:

核心问题:对象切片与多态失效

你定义的三个列表liI、liD、liS的类型是std::list<SimpleList<std::string>>,这意味着它们存储的是SimpleList基类的值对象。当你在Create函数里创建Stack或Queue对象,然后push_back到列表中时,会发生对象切片——派生类的特有部分会被砍掉,只保留基类的内容。这就导致:

  • 后续通过迭代器访问的都是SimpleList基类对象,调用push时执行的是基类里的空实现,而不是Stack/Queue中重写的版本;
  • 你以为在修改原来的Stack/Queue,实际上操作的是被切片后的基类副本,自然看不到变化。

另外,你的IsIn函数传参是std::list<SimpleList<std::string>> li,这会拷贝整个列表,不仅效率低,还可能导致判断逻辑出现问题,应该传引用。

还有SimpleList的几个成员函数逻辑有问题:

  • addEnd里的if(size > 0) {(*end).next = temp;}是错误的,这会让旧的end的next指向自己,形成循环链表,导致后续remove操作出错;
  • remove函数返回的是&((*start).data),当start被移动后,这个指针会变成悬空指针,非常危险,应该直接返回值而不是指针。

修复方案

1. 改用智能指针存储多态对象

把列表的类型改成存储std::unique_ptr<SimpleList<std::string>>,这样可以安全地存储派生类对象,实现多态,同时避免内存泄漏。

2. 修正Create函数

用std::make_unique创建Stack/Queue对象,然后push_back到列表中,避免对象切片。

3. 修正所有涉及列表访问的函数

因为现在存储的是指针,所以访问成员时要改用->而不是.,同时修改IsIn、Push、Pop等函数的逻辑适配指针。

4. 修复SimpleList的成员函数bug

修正addEnd和remove的逻辑错误。

修改后的完整代码

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <string>
#include <list>
#include <memory>
#include <stdexcept>

using namespace std;

template <class T>
class SimpleList {
    struct Node {
        T data;
        Node* next;
        Node(T datI, Node* nextI) : data(datI), next(nextI) {}
    };
protected:
    Node* start;
    int size;
    Node* end;
    std::string name;
public:
    SimpleList(std::string title) : name(title), size(0), start(nullptr), end(nullptr) {}
    
    virtual ~SimpleList() {
        Node* current = start;
        while (current != nullptr) {
            Node* next = current->next;
            delete current;
            current = next;
        }
    }

    void addFront(T element) {
        Node *temp = new Node(element, start);
        if (size == 0) {
            end = temp;
        }
        start = temp;
        size++;
    }

    void addEnd(T element) {
        Node *temp = new Node(element, nullptr);
        if (size == 0) {
            start = temp;
            end = temp;
        } else {
            end->next = temp;
            end = temp;
        }
        size++;
    }

    T remove() {
        if (size == 0) {
            throw std::runtime_error("List is empty");
        }
        Node* tempNode = start;
        T data = tempNode->data;
        start = start->next;
        delete tempNode;
        size--;
        if (size == 0) {
            end = nullptr;
        }
        return data;
    }

    virtual void push(T element) = 0;
    virtual T pop() { return remove(); }
};

template <class T>
class Stack : public SimpleList<T> {
public:
    Stack(std::string title) : SimpleList<T>(title) {}
    void push(T element) override {
        this->addFront(element);
    }
};

template <class T>
class Queue : public SimpleList<T> {
public:
    Queue(std::string title) : SimpleList<T>(title) {}
    void push(T element) override {
        this->addEnd(element);
    }
};

std::list<std::unique_ptr<SimpleList<std::string>>> liI;
std::list<std::unique_ptr<SimpleList<std::string>>> liD;
std::list<std::unique_ptr<SimpleList<std::string>>> liS;

bool IsIn(std::string title, const std::list<std::unique_ptr<SimpleList<std::string>>>& li) {
    for (const auto& ptr : li) {
        if (ptr->name == title) {
            return true;
        }
    }
    return false;
}

std::string Pop(std::vector<std::string> para, std::list<std::unique_ptr<SimpleList<std::string>>>* li) {
    if (!IsIn(para[1], *li)) {
        return "\nERROR: This name does not exist!\n";
    }
    for (auto& ptr : *li) {
        if (ptr->name == para[1]) {
            try {
                return "\nValue popped: " + ptr->pop() + "\n";
            } catch (const std::runtime_error& e) {
                return "\nERROR: " + std::string(e.what()) + "\n";
            }
        }
    }
    return "";
}

std::string Push(std::vector<std::string> para, std::list<std::unique_ptr<SimpleList<std::string>>>* li) {
    if (!IsIn(para[1], *li)) {
        return "\nERROR: This name does not exist!\n";
    }
    for (auto& ptr : *li) {
        if (ptr->name == para[1]) {
            ptr->push(para[2]);
            return "\n";
        }
    }
    return "";
}

std::string Create(std::vector<std::string> para, std::list<std::unique_ptr<SimpleList<std::string>>>* li) {
    if (IsIn(para[1], *li)) {
        return "\nERROR: This name already exists!\n";
    }
    if (para[2] == "stack") {
        li->push_back(std::make_unique<Stack<std::string>>(para[1]));
    } else {
        li->push_back(std::make_unique<Queue<std::string>>(para[1]));
    }
    return "\n";
}

std::string Processing(std::vector<std::string> para) {
    std::string message;
    if (para[0] == "create") {
        if (para[1][0] == 'i') {
            message = Create(para, &liI);
        } else if (para[1][0] == 's') {
            message = Create(para, &liS);
        } else {
            message = Create(para, &liD);
        }
    } else if (para[0] == "push") {
        if (para[1][0] == 'i') {
            message = Push(para, &liI);
        } else if (para[1][0] == 's') {
            message = Push(para, &liS);
        } else {
            message = Push(para, &liD);
        }
    } else if (para[0] == "pop") {
        if (para[1][0] == 'i') {
            message = Pop(para, &liI);
        } else if (para[1][0] == 's') {
            message = Pop(para, &liS);
        } else {
            message = Pop(para, &liD);
        }
    }
    return message;
}

int main() {
    std::vector<std::string> vec;
    vec.push_back("create");
    vec.push_back("i1");
    vec.push_back("queue");
    std::cout << Processing(vec);
    
    vec.clear();
    vec.push_back("push");
    vec.push_back("i1");
    vec.push_back("500");
    std::cout << Processing(vec);
    
    vec.clear();
    vec.push_back("pop");
    vec.push_back("i1");
    std::cout << Processing(vec);

    vec.clear();
    vec.push_back("pop");
    vec.push_back("i1");
    std::cout << Processing(vec);
    
    return 0;
}

关键修改点说明

  1. 智能指针存储:用std::unique_ptr存储SimpleList的派生类对象,完美解决对象切片问题,保证多态生效,同时自动管理内存避免泄漏。
  2. 纯虚函数与虚析构:把push改成纯虚函数,强制派生类必须实现;添加虚析构函数,确保派生类对象能被正确析构。
  3. 修正SimpleList的bug:
    • addEnd函数修复了循环链表的问题,正确维护链表的尾节点;
    • remove函数改为返回值,避免悬空指针,同时添加异常处理空列表的情况。
  4. 传参优化:IsIn函数改为传列表的const引用,避免不必要的拷贝,提升效率。
  5. 逻辑修正:Processing函数里的条件判断改成else if,避免多个if同时触发的逻辑错误。

现在运行修改后的代码,你会发现push和pop操作都能正确作用到对应的Queue/Stack对象上了,输出应该是:

Value popped: 500

ERROR: List is empty!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:42:46