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

时间:2014-03-10 15:23:09

标签: 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, 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());
}

DeleteRegistered

void Token::DeleteRegistered() {
    for (size_t i = 0; i < Token::registered.size(); ++i) {
        delete Token::registered[i];
    }
}

在我的代码中,许多不同的类存储指向子类的指针容器,这些子类最终派生自Token。

为了避免两次或更多次删除对象,我将对所有已分配实例的引用存储起来,并使用一个静态方法将其全部删除。

在执行完所有操作后调用方法DeleteRegistered

现在,我的问题:

当我调用Token::DeleteRegistered时(在程序退出之前会发生几行,它会失败并在调试中显示以下内容:

File: f:\dd\vctools\crt\crtw32\misc\dbgdel.cpp
Line: 52

Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

The memory, just one line before the programs crashes

由于所有Token个实例都没有确定的范围,我想出了这个设计,对我来说,目前似乎没问题。

什么可能导致此错误?

修改 析构函数是我的后期添加,评论它仍然显示上面的错误。 delete甚至无法删除容器中的第一个项目。

2ND编辑: 我如何使用Token

的示例
this->parser.Operators.Add(new RefBinaryOperator(
    "Assignment", "=", 14, RefBinaryOperator::Assign
));

注意:RefBinaryOperator是Token(非直接)的子类,最终调用Token的构造函数。

例如,我从Token容器中提取指向Operators的指针,并将它们分配给其他结构。一切都完成后,我打电话给DeleteRegistered

最终编辑:

我通过将令牌析构函数声明为virtual

来实现它

Does delete work with pointers to base class?

2 个答案:

答案 0 :(得分:8)

正在发生的事情是Token::~Token()你在erase向量中调用registered,这会使你注意到问题的for循环中使用的索引无效。您需要记住,一旦在该向量上调用erase,就需要正确调整for循环索引。如果保留当前的析构函数,则DeleteRegistered

可以使用以下内容
void DeleteRegistered() {
  while(!Token::registered.empty())
    delete *Token::registered.begin();
}

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

答案 1 :(得分:2)

void Token::DeleteRegistered() {
    for (size_t i = 0; i < Token::registered.size(); ++i) {
        delete Token::registered[i];
    }
}

以上不会做你想要的。它将从registered中删除第一个(第0个)元素。第二个元素现在成为第一个元素(第0个元素),但现在i将是1.您的循环将仅删除Token::registered中的所有其他元素。它泄漏了。

处理此问题的一种方法:在向量不为空时,继续删除第一个或最后一个元素。我建议删除最后一个元素,因为它更符合向量的工作方式。删除第一个元素直到向量为空包括每步重建向量。

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