我编写了一个解释器,其中每个关键字,语法符号或运算符的基类为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)
由于所有Token
个实例都没有确定的范围,我想出了这个设计,对我来说,目前似乎没问题。
什么可能导致此错误?
修改
析构函数是我的后期添加,评论它仍然显示上面的错误。 delete
甚至无法删除容器中的第一个项目。
2ND编辑:
我如何使用Token
:
this->parser.Operators.Add(new RefBinaryOperator(
"Assignment", "=", 14, RefBinaryOperator::Assign
));
注意:RefBinaryOperator是Token
(非直接)的子类,最终调用Token
的构造函数。
例如,我从Token
容器中提取指向Operators
的指针,并将它们分配给其他结构。一切都完成后,我打电话给DeleteRegistered
。
最终编辑:
我通过将令牌析构函数声明为virtual
:
答案 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();
}
}