是否存在可能导致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
可以将哪种语句视为免除例外?
答案 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
noexcept
或throw()
最后一点也适用于C ++的所有隐式函数调用:default / copy / move构造函数,重载运算符,析构函数(请注意那些默认为noexcept
)和转换运算符。
如果您对某个特定表达式有疑问,可以使用noexcept
运算符让编译器告诉您该表达式在理论上是否可能抛出。