【发布时间】:2014-03-10 15:23:08
【问题描述】:
我写了一个解释器,其中每个关键字、语法符号或运算符都有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 的子类的指针容器。
为了避免删除对象两次或更多次,我存储了对所有分配实例的引用,并有一个静态方法将它们全部删除。
所有操作执行完毕后调用DeleteRegistered方法。
现在,我的问题:
当我调用Token::DeleteRegistered 时(在程序退出前几行发生,它会失败并且在调试中显示以下内容:
File: f:\dd\vctools\crt\crtw32\misc\dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
由于所有Token 实例都没有真正定义的范围,因此我提出了这个设计,在我看来目前还可以。
什么会导致这个错误?
编辑:
析构函数是我后期添加的,将其注释掉仍然会显示上述错误。 delete 甚至无法删除容器中的第一项。
第二次编辑:
我如何使用Token的一个例子:
this->parser.Operators.Add(new RefBinaryOperator(
"Assignment", "=", 14, RefBinaryOperator::Assign
));
注意:RefBinaryOperator 是Token 的子类(非直接),最终调用Token 的构造函数。
例如,我从Operators 容器中提取指向Tokens 的指针,并将它们分配给其他结构。一切完成后,我打电话给DeleteRegistered。
最终编辑:
我通过将 Token 析构函数声明为 virtual 来使其工作:
【问题讨论】:
-
由于每个令牌将在
Token生命周期内在该列表中注册/注销,您最终可能会删除在堆栈或另一个类中定义的令牌。另外,如何创建令牌? -
嗯,
Token::DeleteRegistered()不会删除大部分对象,但我不知道这会如何导致崩溃。您是否正在使用id成员做任何事情?删除对象后,ids 将停止匹配,您将获得多个具有相同 ID 的实例... -
我不知道它是否会导致您的问题,但您需要一个虚拟析构函数。也无法确保所有实例都是用
new创建的;你如何确保所有这些都是可删除的? -
In order to avoid deleting objects twice or more, I store references to all of the allocated instances,也许您应该投资使用诸如 std::shared_ptr 之类的智能指针,而不是尝试跟踪实例数。使用 shared_ptr,一旦 remove() 完成它的工作,就是这样。你不需要那个静态成员数组。 -
@Dennis:“你能删除堆栈分配的对象吗?” - 不,你不能。这个设计要求所有东西都用
new创建;这是失败的可能原因之一。
标签: c++ memory-management