【发布时间】:2021-07-20 19:38:36
【问题描述】:
以下是我目前正在处理的一个大型遗留项目中出现的问题的一个最小示例。
我有一个 main 函数,它应该创建一个新对象 ob 一个全局对象指针 B* B。
由于配置错误,这没有完成,并且调用了非静态方法b->do_something()。
我的期望是这样做会导致分段错误。
代码确实会产生分段错误,但仅在比较 a == nullptr 时。
这让我非常困惑,因为我正在寻找 a 的初始化问题。
我不知道即使该对象从未初始化,也可以调用对象的非静态方法。
我的问题是将来如何防止这种混乱?那么如何在调用 NULL 对象的非静态方法时使执行崩溃呢?
我还不满意的可能解决方案:
- 将每次调用
b->do_something()包装为if(b != nullptr)- 非常冗长
- 将
do_something()更改为if (&a == nullptr)- 工作但被 clang-tidy 标记(CI 检查失败)
- 根据this
"A reference can not be NULL"
- 将
do_something()扩展为if (this == nullptr || a == nullptr)- 工作但被 clang-tidy 标记(CI 检查失败)
#include <stdio.h>
#include <stdexcept>
class A {};
class B {
A *a = nullptr;
public:
B(){
// Sometimes doing this
a = new A();
}
void do_something() {
if(a == nullptr){ // SegFault appears here because B was never created and accessing this->a evaluates to nullptr->a
throw std::runtime_error("Error");
} else {
printf("Doing Something");
}
}
};
// Global variable
B *b;
int main()
{
// Long code that should have called:
// b = new B();
b->do_something();
return 0;
}
【问题讨论】:
-
与其说
B没有被构造,不如b没有分配给任何东西。作为一个全局变量,它最初应该为空。你可以试试if (b) b->do_something();。 -
理想情况下(为了安全),应该检查每个指针访问。 (一旦检查,您可能会通过引用而不是指针传递以避免额外检查)。