如何捕获空指针异常?

时间:2009-12-01 02:59:34

标签: c++ exception-handling try-catch

  try {
        int* p = 0;
        *p = 1;
    } catch (...) {
        cout << "null pointer." << endl;
    }

我试图抓住这样的异常,但它没有用,有什么帮助吗?

12 个答案:

答案 0 :(得分:56)

C ++中没有“空指针异常”这样的东西。您可以捕获的唯一例外是throw表达式明确抛出的异常(另外,正如Pavel所说,标准operator newdynamic_cast等本质上抛出了一些标准C ++异常)。 C ++中没有其他例外。取消引用空指针,除以零等不会在C ++中生成异常,它会产生未定义的行为。如果您希望在这种情况下抛出异常,则您自己有责任手动检测这些条件并明确执行throw。这就是它在C ++中的工作方式。

您似乎正在寻找的其他任何内容都与C ++语言有关,而是特定实现的特性。例如,在Visual C ++中,系统/硬件异常可以“转换”为C ++异常,但这种非标准功能附带价格,通常不值得付费。

答案 1 :(得分:25)

你做不到。取消引用空指针是一个系统问题。

在Linux上,操作系统会在您的应用程序中引发信号。看看csignal,了解如何处理信号。要“捕获”一个,你将挂钩一个函数,在SIGSEGV的情况下将被调用。在优雅地终止程序之前,您可以尝试打印一些信息。

Windows使用structured-exception-handling。您可以使用instristics __try/__except,如上一个链接中所述。我在我编写的某个调试实用程序中使用函数_set_se_translator的方式(因为它与钩子非常匹配)。在Visual Studio中,确保已启用SEH。使用该函数,您可以挂钩函数以在系统在应用程序中引发异常时调用;在你的情况下,它会用EXCEPTION_ACCESS_VIOLATION来调用它。然后,您可以抛出异常并将其传播回去,就像首先抛出异常一样。

答案 2 :(得分:9)

取消引用null(或指向数组末尾的指针或随机无效指针)会导致未定义的行为。没有便携的方法可以“抓住”它。

答案 3 :(得分:7)

有一种非常简单的方法可以使用try - &gt;在 Visual Studio 中捕获任何类型的异常(除以零,访问冲突等) catch (...)阻止。

一个小项目调整就足够了。只需在项目设置中启用/EHa选项即可。请参阅项目属性 - &gt; C / C ++ - &gt;代码生成 - &gt;将“启用C ++例外”修改为“是和SEH例外”。就是这样!

详情请见: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

答案 4 :(得分:5)

C ++不进行指针检查(尽管我认为有些实现可以)。如果你试图写入空指针,它很可能会崩溃。它不会抛出异常。如果你想要捕获它,你需要在尝试写入之前自己检查指针的值。

答案 5 :(得分:3)

一般情况下你不能。即使你可能就像试图在潜艇上放一个乐队援助一样,也会发生泄漏。

瘫痪的应用程序可能会比崩溃的应用程序造成更大的伤害。我的建议是让它崩溃,然后解决它崩溃的原因。冲洗。重复。

答案 6 :(得分:1)

正如其他人所说,你不能用C ++做到这一点。

如果我可以提出更广泛的观点:即使在一种允许你捕捉它的语言中,更好的做法是不要触及空指针。当一个错误已经在你面前被炸毁,然后决定继续前进就像它没有发生一样,这不是一个好的编码策略。像空指针取消引用,堆栈溢出等等,应该被视为灾难性事件并且防御性地避免,即使您的语言允许您对它做出不同的反应。

答案 7 :(得分:1)

没有独立于平台的方法来做到这一点。在Windows / MSVC ++下,您可以使用__try / __除

但我不建议你这样做。你几乎肯定无法从分段错误中正确恢复。

答案 8 :(得分:0)

如果你想,你可以自己做指针检查并抛出......

if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();

所以当然这只是调试问题,nullptr不应该首先发生:)

答案 9 :(得分:0)

简短回答 - 你不能以便携式或标准方式,因为这样的错误可能会破坏过程本身。

答案很长 - 你可以做的比你想象的要多,而且肯定超过刚刚崩溃的程序的默认值。但是,你需要牢记三件事:
1)这些错误比例外更严重,通常不能作为你的逻辑的例外 2)您对它们的检测和库处理将依赖于平台依赖于后端,即使您可以提供一个干净的抽象界面供公众使用。
3)总会有一些非常糟糕的崩溃,你甚至无法在结束前检测到它们。

基本上,像段错误或堆损坏这样的错误不是例外,因为它们会破坏运行程序的实际进程。您编写到程序中的任何内容都是程序的一部分,包括异常处理,因此除了在进程终止之前记录好的错误消息之外的任何事情都是不可取的,在少数情况下这是不可能的。在POSIX中,操作系统使用信号系统报告这些故障,您可以注册回调函数以记录退出前的错误。在Windows中,操作系统有时可以将它们转换为正常的异常,您可以捕获并从中恢复。

然而,最终,你最好的选择就是采取防御措施来对抗这种噩梦。在任何给定的操作系统上都会有一些非常糟糕,即使在原理上,在您的进程终止之前也无法检测到它们。例如,破坏你自己的堆栈指针会让你崩溃,甚至你的POSIX信号回调也永远不会看到它。

答案 10 :(得分:0)

在VC ++ 2013(以及早期版本)中,您可以在例外情况下设置断点:

  1. 按Ctrl + Alt + Delete(这将打开例外对话框)。
  2. 展开“Win32例外”
  3. 确保选中“0xC0000005访问冲突”异常。
  4. 现在再次调试,当空取消引用发生时,将完全命中断点。

答案 11 :(得分:-1)

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;
   }