关于非投掷函数的混淆

Alc*_*ott 5 c++ exception-specification

我有两个关于非投掷功能的问题:

  1. 为什么要使一个函数不抛?

  2. 如何使功能不抛?如果函数内部的代码实际可能throw,那么我还应该让它不抛?

这是一个例子:

void swap(Type t1, Type t2) throw()
{
    //swap
}
Run Code Online (Sandbox Code Playgroud)

如果代码中swap根本不会抛出,我还应该追加throw()吗?为什么?

Gor*_*pik 5

throw()(或noexcept在 C++11 中)之所以有用,有两个原因:

  1. 它允许编译器在其优化中更加积极。
  2. 它告诉函数用户他们可以在自己的非抛出函数中使用这个函数。

非抛出函数对于编写异常安全代码非常重要。例如,编写异常安全的通常方法operator=是通过非抛出swap()函数。

另一方面,其他异常规范是无用的,在当前标准中已被合理弃用。它们根本不能与模板很好地混合,而且执行起来成本太高。

现在,如果您noexcept在可能实际抛出的函数中使用规范,则所有赌注都将取消。即使您的编译器在异常离开函数时不终止程序(例如,VS 出于运行时效率的原因不会这样做),您的代码也可能由于优化而无法执行您的想法。例如:

void f() noexcept
{
  a();
  b();
}
Run Code Online (Sandbox Code Playgroud)

如果a()实际抛出并b()有副作用,函数行为将是不可预测的,因为您的编译器可能决定在b()之前执行a(),因为您已经告诉它不会抛出任何异常。

编辑:现在是问题的第二部分:如何使函数不抛出?

首先你需要问自己你的函数是否真的应该是非抛出的。例如:

class C
{
  C* CreateInstance()
  {
    return new C();
  }
}
Run Code Online (Sandbox Code Playgroud)

由于运算符new可以抛出std::bad_alloc,因此CreateInstance()可以抛出。您可以尝试使用 try-catch 块来避免它,处理或吞下可能在try块内抛出的任何异常,但这真的明智吗?例如:

C* CreateInstance()
{
  try
  {
     return new C();
  }
  catch (...)
  {
     return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

问题似乎解决了,但是您的来电者会准备好CreateInstance()返回null吗?否则,当他们尝试使用该指针时会发生崩溃。此外, astd::bad_alloc通常意味着您的内存不足,您只会推迟问题。

所以要小心:有些函数可以设置为非抛出,但其他函数应该被允许抛出。异常安全不是一件小事。