C++ 异常,what() 函数可以为 NULL 吗?

8

一个捕获的std::exception是否可能有what()为NULL的情况?

下面对e.what()进行检查会不会增加开销?

//...
}
catch (const std::exception& e)
{
  std::string error;
  if(e.what())
    error = e.what();
}
4个回答

13
字符串的内容是由实现定义的,所以我想答案是肯定的。
编辑:取消上面的话。标准说:
virtual const char* what() const throw();
5 Returns: An implementation-defined NTBS.
所以它必须返回一个字符串,而不仅仅是一个指针。并且字符串不能为NULL。正如其他人所指出的那样,很容易推导出异常,其what()确实返回NULL,但我不确定这些事情如何符合标准一致性。当然,如果您正在自己的异常类中实现what(),允许其返回NULL会被认为是非常糟糕的做法。
更多信息,请参见通过继承扩展C++标准库?

虽然它是虚拟的,但糟糕的程序员可能会将其设为NULL。 - JaredPar
1
@j_random_hacker,如果他们选择将返回类型设置为std::string而不是const char*,那么在至少强制执行有效的空字符串方面,这种情况下他们可以做到。但现在为时已晚 :(. - JaredPar
2
@JaredPar 返回一个字符串会涉及到内存分配,如果你想报告内存分配失败,这可能是不可取的。 - anon
4
@网民 - 我会实际上对系统中的所有异常类进行代码审查,并确保它们不返回NULL。在一个给定的系统中可能并不多,通过一些前期工作,您可以节省大量的冗余代码。 - Michael Kohne
2
关键在于为了有正确的继承,必须保留基类的承诺。因此,如果基类函数承诺永远不会返回NULL(似乎在这里是这种情况),则任何派生类必须承诺相同,否则继承就是不适当的(已被破坏)。 - markh44
显示剩余5条评论

5
如果有人继承了std::exception并覆盖了返回NULL的内容,那么这是可能的。
   class CMyException : public std::exception
   {
   ...
       virtual const char * what () const {return NULL;}
   };

尽管Neil在标准中发现了很好的内容,但仍然需要检查NULL。尽管std::exception的子类规范说明它们不应返回NULL,但您的编译器中没有任何强制执行此规定的机制,因此以上代码仍然是合法的。这可能是使用assert的理想情况...
 assert(except.what() != NULL);

或者

 if (except.what() != NULL)
 {
      ... normal processing ...
 }
 else
 {
      assert(false);
 }

因为这是一种可能永远不应该发生的情况,您假设它不应该发生,但仍希望在调试模式下知道当您的假设被证明错误时。然后,您可以纠正您的错误假设或解决可能违反您假设的不正确代码(确保what()不返回NULL)。


1
这在语言上是可能的(即您的代码将编译),但这被C++标准所禁止 - 请参见Neil的答案。 - j_random_hacker
是的,如果你只返回NULL,我不确定它是否违反了对what()的规定,可能会导致未定义行为。 - Johannes Schaub - litb

2
当然可以为空:
class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return NULL;
  }
} myex;

1
可以在编程语言中实现此操作(即您的代码将编译),但这在C++标准中是被禁止的 - 请参见Neil的答案。 换句话说,不要这样做,因为其他人的代码可能依赖于您不这样做。 - j_random_hacker
我认为它并没有被“禁止” - 标准规定了std::exception::what的行为 - 它似乎并没有对从std::exception派生的用户类提出任何要求。 - JoeG

0

正如其他人指出的那样,what()不应该返回空指针,但它可能会。只有在异常情况下才会产生空测试的运行时开销,这种情况下,它可能不太重要。

无论如何,我建议至少使用一个assert

如果代码空间也是一个问题,希望assert、您的测试、代码审查和其他QA足够完整,以便在发货之前跟踪到任何违规的异常。

此外,要小心可以自己抛出异常处理代码(例如,像其他人注意到的那样,在处理std::bad_alloc异常时分配内存的std::string)。


在处理 std::bad_alloc 时分配内存不是一个好主意。对于其他异常,没有理由不使用 std::string。 - Kirill V. Lyadvinsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接