如何捕获空指针异常?[复制]
-
22-07-2019 - |
题
这个问题在这里已经有答案了:
- 捕获访问冲突异常? 8 个答案
try {
int* p = 0;
*p = 1;
} catch (...) {
cout << "null pointer." << endl;
}
我试图像这样捕获异常,但它不起作用,有什么帮助吗?
解决方案
C++ 中不存在“空指针异常”这样的东西。您可以捕获的唯一异常是显式抛出的异常 throw
表达式(另外,正如 Pavel 指出的那样,标准 C++ 本质上抛出的一些标准异常) operator new
, dynamic_cast
ETC)。C++ 中没有其他例外。取消引用空指针、除以零等。在 C++ 中不会生成异常,它会生成 未定义的行为. 。如果您希望在此类情况下引发异常,则您有责任手动检测这些情况并执行以下操作 throw
明确地。这就是 C++ 中的工作原理。
无论您似乎在寻找什么,都与 C++ 语言无关,而是特定实现的功能。例如,在 Visual C++ 中,系统/硬件异常可以“转换”为 C++ 异常,但这种非标准功能是有代价的,通常不值得付出代价。
其他提示
你不能。取消引用空指针是系统事务。
在 Linux 上,操作系统会在您的应用程序中发出信号。看一眼 信号 查看如何处理信号。要“捕获”一个,您需要挂钩一个函数,该函数将在以下情况下被调用 SIGSEGV
. 。在这里,您可以尝试在正常终止程序之前打印一些信息。
Windows 使用 结构化异常处理. 。你可以使用 instristics __try/__except
, ,如上一个链接中所述。我在我编写的某个调试实用程序中执行此操作的方法是使用该函数 _set_se_translator
(因为它与钩子紧密匹配)。在 Visual Studio 中,确保启用了 SEH。使用该函数,您可以挂钩一个函数,以便在系统在应用程序中引发异常时调用;在你的情况下它会调用它 EXCEPTION_ACCESS_VIOLATION
. 。然后,您可以抛出异常并将其传播回来,就像首先抛出异常一样。
取消引用空值(或超出数组末尾的指针,或随机无效指针)会导致未定义的行为。没有可移植的方法来“捕获”它。
有一种非常简单的方法可以捕获任何类型的异常(除以零、访问冲突等) 视觉工作室 使用 try
-> catch (...)
块。
一个小的项目调整就足够了。只需启用 /EHa
项目设置中的选项。看 项目属性 -> C/C++ -> 代码生成 -> 将启用 C++ 异常修改为“Yes With SEH Exceptions”. 。就是这样!
请参阅此处的详细信息:http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
C++ 不进行指针检查(尽管我认为某些实现可以)。如果您尝试写入空指针,它很可能会严重崩溃。它不会抛出异常。如果你想捕获这个,你需要在尝试写入指针之前自己检查指针的值。
一般来说你不能。即使你可以,这也就像试图在发生泄漏的潜艇上贴创可贴一样。
一个瘫痪的应用程序造成的损害比崩溃的应用程序要大得多。我的建议是让它崩溃,然后修复崩溃的原因。冲洗。重复。
正如其他人所说,你不能在 C++ 中做到这一点。
如果我可以提出更广泛的观点:即使在允许您捕获它的语言中,更好的操作也是不要触及空指针。当错误已经在你面前爆炸时发现它,然后决定继续前进,就像它没有发生一样,这并不是一个好的编码策略。像空指针取消引用、堆栈溢出等事情应该被视为灾难性事件并防御性地避免,即使您的语言允许您以不同的方式对其做出反应。
没有独立于平台的方法可以做到这一点。在 Windows/MSVC++ 下你可以使用 __尝试/__除了
但无论如何我都不建议这样做。您几乎肯定无法从分段错误中正确恢复。
如果你愿意,你可以自己检查指针并抛出......
if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();
所以当然这只是为了调试问题, nullptr 一开始就不应该发生:)
简短的回答 - 你不能以可移植或标准的方式,因为这样的错误可能会破坏进程本身。
长答案 - 你可以做的比你想象的更多,而且绝对比程序崩溃的默认情况更多。但是,您需要记住三件事:
1)这些错误比异常更严重,并且通常不能作为逻辑异常出现。
2)即使您可以为公共使用提供干净的抽象接口,您对它们的检测和库处理将取决于后端的平台。
3)总会有一些严重的崩溃,你甚至无法在结束之前检测到它们。
基本上,诸如段错误或堆损坏之类的错误也不例外,因为它们会破坏运行程序的实际进程。您在程序中编写的任何内容都是程序的一部分,包括异常处理,因此除了在进程终止之前记录一条漂亮的错误消息之外,任何其他内容都是不可取的,在少数情况下,这并非不可能。在 POSIX 中,操作系统使用信号系统来报告此类错误,并且您可以注册回调函数以在退出之前记录错误。在 Windows 中,操作系统有时可以将它们转换为看起来正常的异常,您可以捕获这些异常并从中恢复。
然而,最终,您最好的选择是编写防御性代码来应对此类噩梦。在任何给定的操作系统上,都会有一些问题非常糟糕,以至于您无法在进程终止之前检测到它们,即使原则上也是如此。例如,损坏您自己的堆栈指针可能会导致您严重崩溃,甚至您的 POSIX 信号回调也看不到它。
在 VC++ 2013(以及早期版本)中,您可以在异常上放置断点:
- 按 Ctrl + Alt + Delete(这将打开异常对话框)。
- 展开“Win32 例外”
- 确保检查“0xC0000005 访问冲突”异常。
现在再次调试,当空取消引用发生时,将准确命中断点。
C++ 中不存在 NULL 指针异常,但您仍然想捕获相同的异常,那么您需要为其提供自己的类实现。
下面是相同的示例。
class Exception {
public:
Exception(const string& msg,int val) : msg_(msg),e(val) {}
~Exception( ) {}
string getMessage( ) const {return(msg_);}
int what(){ return e;}
private:
string msg_;
int e;
};
现在基于 NULL 指针检查它可以像这样抛出, throw(Exception("NullPointerException",NULL));
下面是捕获相同内容的代码。
catch(Exception& e) {
cout << "Not a valid object: " << e.getMessage( )<< ": ";
cout<<"value="<<e.what()<< endl;
}