try块的语法如下:
try compound-statement handler-sequence
handler-sequence 是一个或多个处理程序组成的序列,具有以下语法:
catch (type-specifier-seq declarator) compound-statement
catch (...) compound-statement
这与其他控制语句(如if、while、for等)不同。 这些语句的语法如下:
if (condition) statement-true else statement-false
while (condition) statement
for (init-statement
etc.
现在的问题是为什么try块中需要复合语句而不是单个语句?
考虑以下代码:
int main()
{
try g(); catch (std::runtime_error e) handleError(e);
}
我知道,按值捕获是一种不好的做法(例如可能存在对象切片等问题),但是为了防止关于异常存储期的讨论并使推理更加容易,我这样做了。
现在考虑一下'e'的存储期和链接。您所期望的是,在调用handleError函数之前只能引用'e',但在调用完成后不能引用。它应该具有此“范围”内的自动存储期和无链接。这可能可以通过隐式定义类似其他语句中的局部范围来实现,但将异常声明看起来像函数参数可能是一个更好的想法。因此需要块(复合语句)。请看下面。
现在考虑一下try和之后的语句。没有理由在那里使用try关键字,也没有理由使用复合语句,但语法可能会变得模糊和复杂。
这就是Stroustrup在《C++异常处理》中对此的看法:Exception Handling for C++
It might be possible to simplify the
try { ... } catch (abc) { ... }
syntax by removing the apparently redundant try keyword,
removing the redundant parentheses, and by allowing a handler
to be attached to any statement and not just to a block. For
example, one might allow:
void f()
{
g(); catch (x1) { }
}
as an alternative to - 28 -
void f()
{
try { g(); } catch (x1) { }
}
The added notational convenience seems insignificant and may not
even be convenient. People seem to prefer syntactic constructs that
start with a prefix that alerts them to what is going on, and it may
be easier to generate good code when the try keyword is required.
并在更详细的解释之后:
Allowing exception handlers to be attached to blocks only and not to
simple statements simplifies syntax analysis (both for humans and
computers) where several exceptions are caught and where nested
exception handlers are considered (see Appendix E). For example,
assuming that we allowed handlers to be attached to any statement
we could write:
try try f(); catch (x) { ... } catch (y) { ... } catch (z) { ... }
The could be interpreted be in at least three ways:
try { try f(); catch (x) { ... } } catch (y) { ... } catch (z) { ... }
try { try f(); catch (x) { ... } catch (y) { ... } } catch (z) { ... }
try { try f(); catch (x) { ... } catch (y) { ... } catch (z) { ... } }
There seems to be no reason to allow these ambiguities even if there
is a trivial and systematic way for a parser to chose one
interpretation over another. Consequently, a { is required after a
try and a matching } before the first of the associated sequence of
catch clauses.
正如Stroustrup所说,没有花括号,语句的含义可能会因规则而异,您可能需要加上花括号来澄清意图。我们能否像Stroustrup的示例那样使用if语句创建一些复杂的语句呢?当然可以,例如:
if (c1) if (c2) f(); else if (c3) g(); else h();
这实际上等同于:
if (c1) { if (c2) f(); else { if (c3) g(); else h(); } }
但我认为这比try块的情况少了问题。if语句有两种语法:
if (condition) statement-true
if (condition) statement-true else statement-false
因为有时候没有else动作是合理的。但是一个没有catch子句的try块是没有意义的。可以省略“try”,但不实用,正如Stroustrup所说,但如果你指定了try块,则不能省略catch子句。除此之外,可能会有多个与相同try块相关的catch,但只有一个基于异常类型和catch子句的顺序规则被执行。
现在,如果if-else的语法改变为:
if (condition) compound-statement-true else compound-statement-false
然后,你必须像这样编写if-else:
if (c1) { f(); } else { if (c2) { g(); } else { h(); } }
注意到没有'elseif'关键字,也没有'else if'的特殊语法。我认为即使是那些坚持「始终加大括号」的人也不喜欢这样写,而会写成这样:
if (c1) { f(); } else if (c2) { g(); } else { h(); }
我认为这不是将语法定义为上述形式并引入“elseif”关键字或为“else if”定义特殊语法的充分理由。