【发布时间】:2011-06-19 14:06:00
【问题描述】:
我正在使用xlC 编译器在AIX 上构建Cppcheck(请参阅previous question)。 Checker 类都派生自 Check 类,其构造函数将每个对象注册到全局列表中:
check.h
class Check {
public:
Check() {
instances().push_back(this);
instances().sort();
}
static std::list<Check *> &instances();
virtual std::string name() const = 0;
private:
bool operator<(const Check *other) const {
return (name() < other->name());
}
};
checkbufferoverrun.h
class CheckBufferOverrun: public Check {
public:
// ...
std::string name() const {
return "Bounds checking";
}
};
我似乎遇到的问题与instances().sort() 通话有关。 sort() 将调用 Check::operator<(),后者在静态 instances() 列表中的每个指针上调用 Check::name(),但刚刚添加到列表中的 Check 实例尚未完全运行其构造函数(因为它仍在内部Check::Check())。因此,在 CheckBufferOverrun 构造函数完成之前对此类指针调用 ->name() 应该是未定义的行为。
这真的是未定义的行为,还是我在这里遗漏了一个微妙之处?
请注意,我不认为对sort() 的调用是严格要求的,但效果是Cppcheck 以确定的顺序运行其所有检查器。这只会影响检测到错误的顺序的输出,这会导致某些测试用例失败,因为它们期望以特定顺序输出。
更新:上面的问题(大部分)仍然存在。但是,我认为在构造函数中调用sort() 没有引起问题(即通过调用纯虚函数而崩溃)的真正原因是Check::operator<(const Check *) 从未真正被sort() 调用!相反,sort() 似乎改为比较 指针。在g++ 和xlC 中都会出现这种情况,表明 Cppcheck 代码本身存在问题。
【问题讨论】:
-
向
Check构造函数添加一个字符串“name”参数,并让后代在构造时提供一个值。将name()设为非虚拟并返回构造函数传入的值。此处显示的Check构造函数的其余部分可以保持原样。 -
@Rob Kennedy:这是一个很好的解决方案,我会向维护人员提出这个建议。
-
是的,并考虑是否值得为实例使用集合而不是列表 - 这可能比在每次插入后显式调用排序更快。顺便说一句,您的 operator
标签: c++ constructor pure-virtual