什么可以(以及什么不可以)在c ++中抛出异常?

时间:2017-03-16 11:21:00

标签: c++ exception

是否存在可能导致c ++异常的“代码语句”的完整列表(可能是递归定义的)?像这样:

1)throw声明(自然地)

2)致电new

3)调用标准库中可以抛出的任何函数。

4)调用任何包含1-3的操作的用户定义函数(包括构造函数)。

5)还有别的吗?在堆栈上分配本地对象,对内置类型进行操作,解除引用指针,类型转换 - 是否能够抛出?

6)其他一切都没有例外。

无异常我并不是指总是成功的操作。肯定不取消引用指针。但是将它包装在try-catch块中仍然没有意义,考虑异常安全的函数解除引用指针等等。因此,成功或导致未定义行为的代码可以被视为无异常。

更新。尽管我的最后一段我仍然有一个评论,未定义的行为也可以抛出,所以让我解释一下我的意思。请考虑以下代码:

void bar();
Class C{
...
public:
  foo() {
    something_that_breaks_class_invariants;
    bar();
    something_that_restores_class_invariants;
  }
}

如果我正确理解异常安全是什么,那么如果bar()可以抛出异常,那么这段代码就不好了。我应该改变语句的顺序,或者我应该包装{{ 1}}在bar()块中,恢复类不变量并进一步传播异常。

但是如果bar()成功返回或导致未定义的行为(因为,我不知道,还有其他东西被破坏),那么try-catch就可以了。 foo()无法执行任何操作,也不应关心foo()可能未定义的行为。从这个意义上讲,bar()无异常,可以标记为bar()等。

所以我的问题是:noexcept可以将哪种语句视为免除例外?

3 个答案:

答案 0 :(得分:0)

您的列表已基本完成。确实有一个投掷者可以投掷:dynamic_cast<Derived&>。这是因为没有空引用。 dynamic_cast<Derived*>返回空指针而不是抛出。

所有情况下,在评估表达式时会抛出异常。变量定义只有在包含表达式时才会抛出,例如在初始化程序中或构造函数内部。

&#34;未定义的行为&#34;有点红鲱鱼。您根本无法推断出具有未定义行为的C ++程序,甚至不能解释在该UB之前可能发生的事情。这意味着每当我们推理定义的C ++行为时,我们都不会假设UB。

答案 1 :(得分:0)

答案很简单:任何使用无法运算的操作符或函数的语句都不能被抛出。以下是一些例子:

template <class T> T foo(const T& arg) { return arg; }    //can throw (copy constructor!)
template <class T> void foo(T a, T b) { a+b; }    //can throw (+ is overloadable)

template <class T>
void foo(T iter, T end) {
    for(; iter < end; iter++) {    //both the < and the ++ operator can throw
        iter->bar();    //even the -> operator is overloadable and can throw
    }
}

简而言之,只要您不了解所涉及的类型(通常是模板的情况),您几乎必须将任何语句称为抛出语句。

Afaik,唯一有效的防御措施,首先不允许例外。

答案 2 :(得分:0)

是的,可以详尽地定义可以引入C ++的内容列表。

  • throw表达
  • new可以抛出bad_alloc
  • dynamic_cast可以抛出bad_cast
  • typeid可以抛出bad_typeid
  • 对非noexceptthrow()
  • 的函数的任何调用

最后一点也适用于C ++的所有隐式函数调用:default / copy / move构造函数,重载运算符,析构函数(请注意那些默认为noexcept)和转换运算符。

如果您对某个特定表达式有疑问,可以使用noexcept运算符让编译器告诉您该表达式在理论上是否可能抛出。