2017-03-16 32 views
4

有没有可能导致C++异常的“代码语句”的完整列表(可能是递归定义的)?事情是这样的:什么(和什么不能)在C++中抛出异常?

1)throw声明(自然)

2)调用new

3)调用从标准库被记录在案,以便能够抛出任何功能。

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

5)别的吗?在堆栈上分配本地对象,对内置类型进行操作,取消引用指针,类型转换 - 是否可以抛出?

6)其他一切都是免费的。

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

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

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

如果我正确理解什么异常安全之约,然后如果bar()可以抛出异常,该代码是坏的。我应该改变语句的顺序,否则我应该把bar()换成try-catch块,恢复类不变量并进一步传播异常。如果bar()成功返回或导致未定义的行为(因为我不知道,其他东西已损坏),那么foo()就可以。 foo()不能做任何事情,不应该关心bar()的未定义行为。在这个意义上bar()是免费的,可以标记为noexcept

所以我的问题是:什么样的语句可以在bar()认为它是免费的这种感觉?

+7

先假设一切都可以抛出。那么如果你需要证明它没有。这是一个XY问题的味道。 –

+1

任何未定义的行为都可能导致抛出异常...... –

+0

将'std :: vector :: at'包装在try-catch中并没有什么意义。 – chris

回答

0

是的,可以用C++抛出的东西的列表可以被详尽定义。

  • throw表达
  • new可以抛出bad_alloc
  • dynamic_cast可以抛出bad_cast
  • typeid可以抛出bad_typeid
  • 任何调用一个函数,不是noexceptthrow()

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

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

0

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

全部个案中,在评估表达式时引发例外。变量定义只有在包含表达式时才会抛出,例如在初始化程序或构造函数中。

“未定义行为”位是红色鲱鱼。你根本无法推理出一个具有未定义行为的C++程序,甚至不能理解在该UB之前可能发生的事情。这意味着,只要我们推理定义的C++行为,我们就不会假设UB。

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,唯一有效的防御措施,不允许例外。

相关问题