给定如下代码:
void f()
{
int i;
i = 0;
}
由于简单的分配,系统是否有可能引发异常?
[编辑:对于那些说“不会发生异常”的人,您能否指出 C++ 标准中说明这一点的部分的方向?我很难找到它。]
尽管您可能很难在标准中找到它的保证,但一个简单的经验法则是,任何在 C 中合法的东西都可能无法抛出。[编辑:我所知道的最接近这种效果的直接陈述是在§15/2,它说:
执行throw 表达式的代码被称为“抛出异常”;[...]
反过来看,不执行 throw 表达式的代码不会引发异常。]
投掷基本上限于两种可能性:第一种是调用UB。第二个是做一些 C++ 独有的事情,例如分配给重载的用户定义类型operator =
,或使用new
表达式。
编辑:就作业而言,它可以抛出很多方法。显然,加入赋值运算符本身就可以做到这一点,但还有很多其他的。举例来说,如果源类型与目标类型不匹配,您可能会通过源中的强制转换运算符或目标中的构造函数获得转换——其中任何一个都可能抛出。
有很多看起来像作业的东西可以以一种或另一种方式抛出:
int operator"" _t(const char *) { throw 0; } // C++11 user defined literal
struct foo {
foo(int) { throw 0; }
operator int() { throw 0; }
foo& operator=(int) { throw 0; }
};
int main() {
int i;
i = 0; // can't throw
i = 0_t; // User defined literal throws
foo f = 0; // Constructor throws
i = f; // conversion operator throws
f = 0; // assignment throws
f = f; // both conversion and assignment would like to throw
}
(包括来自 C++11 的新版本)
如果您担心将0
(具有 type int
)分配给
int
,则标准的第 5.17 节非常准确地指定了分配操作的语义,并且不会发生异常。如果您担心将任意表达式分配给int
,第 5.17 节说“表达式被隐式转换为左操作数的 cv 非限定类型。”取决于右操作数的实际类型:
如果它是整数类型,如果实际值不能在 an 中表示int
,则结果是实现定义的(C 标准更明确:它必须产生int
带有实现定义值的 an,否则您将获得实现定义的信号)
如果它是一个浮点值,则结果是未定义的行为,如果截断为零后的值不能在 an 中表示int
,则行为未定义(因此您可能会遇到异常)
如果它是用户定义的类型,则将调用用户定义的转换运算符。这可能会引发异常。
如果您担心分配其他类型:对于每组非类类型,都有一个类似上面的规则列表,但唯一可能的例外是类型转换的结果。对于类类型,operator=
将使用 。这可能会引发异常,具体取决于其中的内容。
它只能在一种情况下抛出异常:当operator=()
这两种类型重载时抛出;类似地,当需要转换时,转换构造函数 oroperator T()
也可以抛出。这取决于确切的实现 - 要确定它是否会抛出,请在您正在使用的库的文档中查找有关它的信息。
如果它只是一个int
,那么不 - 它不会抛出。
如果它是更复杂的东西,例如向量,那么它可能会由于多种原因而抛出(例如分配失败或来自辅助线程的更改)。