在阅读clickhouse代码的过程中,发现有一种函数定义形式很怪异,一度以为是代码写错了。。。
int?main()?
try
{
????XXX
}
catch?(DB::Exception?&?e)
{
????XXX
}
形式如上,函数名之后怎么能不加花括号呢?这是不是不符合语法?深入了解之后发现原来是我孤陋寡闻了。
https://en.cppreference.com/w/cpp/language/function-try-block
上面的代码其实跟下面差不多
int?main()?
{
????try
????{
????????xxx
????}
????catch?(DB::Exception?&?e)
????{
????????xxx
????}
}
第一种看起来比较怪异的形式在cpp里叫做function-try-block, 第二种就是我们常见的function-body
那么function-try-block主要使用于哪种场合呢?它是不是能捕获到所有的异常呢?让我们看下文档
The?primary?purpose?of?function-try-blocks?is?to?respond?to?an?exception?thrown?from?the?member?initializer?list?in?a?constructor?by?logging?and?rethrowing,?modifying?the?exception?object?and?rethrowing,?throwing?a?different?exception?instead,?or?terminating?the?program.?They?are?rarely?used?with?destructors?or?with?regular?functions.
Function-try-block?does?not?catch?the?exceptions?thrown?by?the?copy/move?constructors?and?the?destructors?of?the?function?parameters?passed?by?value:?those?exceptions?are?thrown?in?context?of?the?caller.
Likewise,?function-try-block?of?the?main()?function?does?not?catch?the?exceptions?thrown?from?the?constructors?and?destructors?of?static?objects?(except?for?the?constructors?of?function-local?statics).
function-try-block这种形式主要用于类构造函数和main函数中,而很少使用在类析构函数和其他常规函数中。
-
在类的构造函数中,function-try-block能够捕获到初始化列表中的异常,用户可以在catch block中打印日志、修改异常、重抛异常。需要注意的是,function-try-block无法捕获传值参数的复制/移动构造函数/析构函数中抛出的异常,这些异常会传递到function-try-block调用者的上下文中。 -
在main函数中,function-try-block能够捕获try块中的异常,但是无法捕获静态对象构造和析构过程中抛出的异常
相关实例如下所示:
#include?<exception>
#include?<iostream>
class?MyException?:?public?std::exception?
{
public:
????MyException(const?char*?msg)?:?msg(msg)?{?}
????virtual?const?char*?what()?const?throw()?{?return?msg.c_str();?}
private:
????std::string?msg;
};
class?M
{
public:
????explicit?M(size_t?size)
????{
????????throw?MyException("exception?from?constructor");
????}
????M(const?M?&?other)
????{
????????throw?MyException("exception?from?copy?constructor");
????}
????M(M?&&?other)
????{
????????throw?MyException("exception?from?move?constructor");
????}
????
????~M()
????{
????????//?throw?MyException("exception?from?destructor");
????}
};
class?A
{
public:
????explicit?A()?try:?
????????????m1(10),?
????????????m2(m1),?
????????????m3(std::move(m2))
????{
????}
????catch?(std::exception?&?e)
????{
????????std::cout?<<?"catch?exception?in?A:A:?"?<<?e.what()?<<?std::endl;
????????throw;
????}
????~A()?=?default;
private:
????M?m1;
????M?m2;
????M?m3;
};
int?main()
try
{
????A?a;
}
catch?(std::exception?&?e)
{
????std::cout?<<?"catch?exception?in?main:?"?<<?e.what()?<<?std::endl;
}
执行初始化列表m1(10) 的时候会抛出异常,然后被A::A中的try catch捕捉到,重新抛出到main函数的上下文,接着被main中的try catch捕捉到。因此运行结果为
catch?exception?in?A:A:?exception?from?constructor
catch?exception?in?main:?exception?from?constructor
|