C++ C++;删除对象时出现意外错误

C++ C++;删除对象时出现意外错误,c++,memory-management,C++,Memory Management,我编写了一个解释器,其中每个关键字、语法符号或运算符的基类都是Token class Token { private: static std::vector<Token *> registered; size_t id; std::string name; std::string symbol; public: Token(const std::string& Name, c

我编写了一个解释器,其中每个关键字、语法符号或运算符的基类都是
Token

class Token {
    private:
        static std::vector<Token *> registered;

        size_t id;

        std::string name;
        std::string symbol;

    public:
        Token(const std::string& Name, const std::string& Symbol);
        Token::~Token();

        Token(const Token& rhs) = delete;
        Token& operator =(const Token& rhs) = delete;

        /* ... */

        static void DeleteRegistered();
};
析构函数

Token::Token(const std::string& Name, const std::string& Symbol)
                : name(Name), symbol(Symbol) {
    Token::registered.push_back(this);
    this->id = Token::registered.size();
}
Token::~Token() {
    // Removes 'this' from Token::registered
    Token::registered.erase(std::remove(Token::registered.begin(), Token::registered.end(), this), Token::registered.end());
}
void Token::DeleteRegistered() {
    for (size_t i = 0; i < Token::registered.size(); ++i) {
        delete Token::registered[i];
    }
}
删除已注册的

Token::Token(const std::string& Name, const std::string& Symbol)
                : name(Name), symbol(Symbol) {
    Token::registered.push_back(this);
    this->id = Token::registered.size();
}
Token::~Token() {
    // Removes 'this' from Token::registered
    Token::registered.erase(std::remove(Token::registered.begin(), Token::registered.end(), this), Token::registered.end());
}
void Token::DeleteRegistered() {
    for (size_t i = 0; i < Token::registered.size(); ++i) {
        delete Token::registered[i];
    }
}

由于所有的
Token
实例实际上都没有定义的范围,所以我提出了这个设计,目前对我来说似乎还可以

什么会导致此错误

编辑: 析构函数是我后来添加的,注释出来仍然显示了上面的错误。
delete
甚至无法删除容器中的第一个项目

第二次编辑: 我如何使用
令牌的示例:

this->parser.Operators.Add(new RefBinaryOperator(
    "Assignment", "=", 14, RefBinaryOperator::Assign
));
注意:RefBinaryOperator是
标记的子类(非直接),它最终调用
标记的构造函数

例如,我从
操作符
容器中提取指向
标记
s的指针,并将它们分配给其他结构。完成所有操作后,我调用
DeleteRegistered

最终编辑:

我通过将令牌析构函数声明为
virtual
,使其正常工作:


发生的情况是,在
令牌::~Token()
中,您正在从
注册的
向量调用
擦除
,这将使您注意到问题的for循环中使用的索引无效。您需要记住,一旦对该向量调用
erase
,就需要正确调整for循环索引。如果保留当前析构函数,则以下函数可以在
DeleteRegistered
中工作:

void DeleteRegistered() {
  while(!Token::registered.empty())
    delete *Token::registered.begin();
}

另外,由于您有许多扩展自
Token
~Token()的类
应变为虚拟,以便正确处理基类的销毁。

由于在
令牌
生存期内,每个令牌都将在该列表中注册/注销,因此您可能会删除堆栈上或其他类中定义的令牌。另外,如何创建令牌?嗯,
Token::DeleteRegistered()
不会删除大多数对象,但我看不出这会导致崩溃。您是否正在使用
id
成员进行任何操作?一旦你删除了一个对象,
id
s将停止匹配,你将得到多个具有相同id的实例……我不知道这是否导致了你的问题,但你需要一个虚拟析构函数。也无法确保所有实例都是使用
new
创建的;如何确保所有实例都可删除?
为了避免删除对象两次或两次以上,我存储对所有已分配实例的引用,
也许您应该投资使用智能指针,例如std::shared\u ptr,而不是试图跟踪实例数。使用shared_ptr,一旦remove()完成了它的工作,就完成了。您不需要那个静态成员数组。@Dennis:“您可以删除堆栈分配的对象吗?”-不,您不能。此设计要求使用
新建
创建所有内容;这是失败的一个可能原因。迭代使用的是索引,而不是迭代器,所以它所做的唯一一件事就是未能删除一半的对象。但我不明白它是如何导致崩溃的。我担心在你的建议下,错误仍然会出现。@fasked:但析构函数(由删除表达式调用)会出现。@fasked在这种情况下你是不正确的,因为令牌析构函数会更改向量OK的大小。我看到你的编辑。说真的,如果您使用了共享的ptr或共享的容器,您这里的问题将大大减少,如果不是完全消失的话。
remove
不会修改
registered
(至少不会以任何方式使迭代器失效),因此,
erase
的参数按哪个顺序求值并不重要。@MikeSeymour-I正确无误。我正在删除(并删除!)我答案的第一部分。问题出在
DeleteRegistered
,而不是
Token::~Token
@DavidHammen正在尝试您的解决方案,它确实成功地删除了前两个
Token
,但后来崩溃了。@Tyymo-正如PaulMcKenzie几分钟前在对您的问题的评论中建议的那样,您应该向我们展示一个简单的工作示例。尽管您的建议不起作用,但它让我找到了代码的真正问题。谢谢
void Token::DeleteRegistered() {
    for (size_t i = 0; i < Token::registered.size(); ++i) {
        delete Token::registered[i];
    }
}