【问题标题】:confusion about non-throw functions关于非抛出函数的混淆
【发布时间】:2012-08-04 05:33:39
【问题描述】:

我有 2 个关于非抛出函数的问题:

  1. 为什么要让函数不抛出?

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

这是一个例子:

void swap(Type t1, Type t2) throw()
{
    //swap
}

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

【问题讨论】:

标签: c++ exception-specification


【解决方案1】:

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

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

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

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

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

void f() noexcept
{
  a();
  b();
}

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

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

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

class C
{
  C* CreateInstance()
  {
    return new C();
  }
}

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

C* CreateInstance()
{
  try
  {
     return new C();
  }
  catch (...)
  {
     return null;
  }
}

问题似乎已解决,但您的调用者是否准备好让CreateInstance() 返回null?如果没有,当他们尝试使用该指针时会发生崩溃。此外,std::bad_alloc 通常意味着您的内存已用完,您只是将问题推迟。

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

【讨论】:

  • 很明确的答案,但我是否应该用throw()/noexcept标记每个函数,我可以确定它不会抛出?
  • @Alcott:如果你认真对待异常安全,我认为你应该这样做。或者至少记录好你的函数抛出的所有异常。
【解决方案2】:

为什么要让函数不抛出?

因此,函数的调用者可以调用它,而无需采取任何措施来处理函数引发的异常。

如何使函数不抛出?如果函数内部的代码实际上可能会抛出,那我还应该让它不抛出吗?

您可以通过将所有可能抛出内部的代码放入 try 块中来使代码不抛出,并在不重新抛出的情况下处理任何异常。

void swap(T t1, T t2) noexcept {
  try {
    // ....
  } catch (const std::exception& ex) {
    // ....
  } catch (...) {
    // ....
  }

}

如果你声称你的函数没有抛出,那么你必须让它不抛出。但这并不意味着添加异常规范,无论如何您都不应该这样做,因为它已被弃用。这意味着您必须确保该函数无论如何都不会抛出。 C++11 关键字noexcept 在这方面为您提供了一些编译时安全性。

【讨论】:

  • 你无法捕捉所有可能被抛出的类型,是吗?
  • @MichałGórny 当然可以。你可以看到上面的catch (...) 子句。只是对于这种捕获的异常,您无能为力(吞下而不知道它是什么或重新抛出它)。
  • @TadeuszKopec:啊,一个人一生都在学习。我一直认为... 有'放任何你想要的东西':D。
  • @MichałGórny 在大多数情况下,是的,但这是省略号 ... 实际上意味着什么的一种情况。例如,也在可变参数模板中。
猜你喜欢
  • 2015-01-05
  • 2021-10-02
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 2017-12-06
  • 1970-01-01
相关资源
最近更新 更多