【问题标题】:No curly braces around main() -- why does this work?main() 周围没有花括号——为什么会这样?
【发布时间】:2012-08-01 19:57:23
【问题描述】:

我正在阅读一本关于 C++ 的书,在关于错误的章节中,它有这个程序(我遗漏了一些小事情,但主要是这个):

int main()
try { 
        // our program (<- this comment is literally from the book)
        return 0;
}
catch(exception& e) {
    cerr << "error: " << e.what() << '\n';
    return 1;
}
catch(...) {
    cerr << "Unknown exception\n";
    return 2;
}

这是编译的,但当然它什么也没做,所以我仍然想知道

  1. 为什么没有一组花括号括住 main() 之后的所有内容?这些块或者我应该称它们为“流行语”(哈!)是否是 main() 的一部分?
  2. 如果它们是函数,为什么在 catch(whatever) 之前没有“int”?
  3. 如果它们不是函数,它们是什么?
  4. re catch(...),我从未见过这样使用省略号。我可以在任何地方使用省略号来表示“任何东西”吗?

【问题讨论】:

标签: c++ syntax error-handling


【解决方案1】:

如果你直接使用 try 块而不是大括号,try 块会捕获函数中发生的所有事情。这在构造函数中很有用,因此您可以在初始化列表中捕获异常。

这将从 bar 的构造函数中捕获异常:

void Foo::Foo() try : bar() {
    // do something
} catch(...) {
    // do something
}

这只会捕获正文中的异常:

void Foo::Foo() : bar() {
    try {
        // do something
    } catch(...) {
        // do something
    }
}

【讨论】:

  • 请注意,在构造函数中的使用是有限的。在 catch 块结束之前,构造函数必须抛出(或追溯),在一般情况下几乎不可能执行任何短的清理。
【解决方案2】:

1 为什么没有一组花括号将 main() 之后的所有内容括起来? ...

有,它只是在左大括号之前有关键字try,而一些catchmain 的结尾之后阻塞。

...这些块是还是我应该称它们为“流行语”(哈!) main() 的一部分?

2 如果它们是函数,为什么在 catch(whatever) 之前没有“int”?

3 如果它们不是函数,它们是什么?

它们是关键字,而不是函数,它们是 main 的一部分,尽管 try 介于 int main() 定义和它的 {} 主体之间。请参阅下面的激励案例以获取另一个示例。

4 re catch(...),我从未见过这样使用省略号。我可以在任何地方使用省略号来表示“任何东西”吗?

在 C++ 中有几个重载的省略号含义。

  • catch(...) 表示捕获任何东西,它就像异常类型的通配符(如果有多个,应该是最后一个捕获)
  • int printf(char *, ...) 表示函数接受一个变量 argument 列表,它完全禁用了参数的类型检查并且很容易出错(但偶尔有用)
  • template &lt;typename... TypePack&gt; 表示模板接受变量 type 列表,这对于元编程非常有用,但在这里完全超出范围
  • #define DEBUG(str, ...) 是一个可变参数宏,类似于可变参数函数

函数级try/catch 块是一种将整个函数体包装在异常处理程序中的方法。所以,这里的主要功能块在try { ... }里面。

IIRC 是专门引入的,它允许构造函数用 try/catch 包装其初始化列表,以处理从子对象构造函数抛出的异常。

例如。 (励志案例)

C::C() try : Base(1), member(2)
{ ...
}
catch (...) {
    // handle Base::Base or member construction failure here
}

请注意,没有其他方法可以捕获从基类或成员子对象构造函数抛出的异常,因为即使您省略了初始值设定项列表,它们也至少会在构造函数主体开始之前进行默认构造。

【讨论】:

    【解决方案3】:

    这是该语言很少使用的功能。您可以将整个函数包含在 try catch 块中:

    void f()
    try 
    {         // function starts here
    ...
    }         // function ends here
    catch (...) 
    {}
    

    该功能很少使用,因为它几乎从来没有用过。在常规函数的情况下,您可以只使用一个覆盖函数所有代码的 try/catch 块,因此在这种情况下不需要该功能。它在构造函数中的功能有限,因为它允许在初始化列表中捕获异常,否则这些异常不能包含在 try/catch 块中。

    但问题是在catch块中可以做的事情很少:构造失败所以必须抛出一个一个异常(catch块可以抛出一个与捕获的不同的异常,但它必须抛出)。同时,您不能真正执行任何清理,因为在捕获异常时您可能不知道初始化列表中的哪些元素抛出了,这意味着您可能不知道(在一般情况下)哪个成员对象是否已构造。

    【讨论】:

      【解决方案4】:

      它是function-try block。是的,这是合法的,但在更多情况下不需要。查看此答案以获取解释。 What is the meaning of this syntax?

      【讨论】:

        【解决方案5】:

        不确定主函数周围缺少花括号,但看起来其他人已经准备好回答了。

        至于您的其他问题,try catch 块不是 main 之外的函数,并且不需要在它们前面加上 int

        try {}: 程序会尝试运行这个块内的任何东西,如果不管什么原因失败了,就会被catch块捕获。

        catch (exception) {}: 当一个异常被抛出时,它会被一个catch块以特定的Exception作为参数捕获,并允许程序员处理这种情况。

        catch (...) {}: 应该捕获任何通过第一个 catch 块的东西..

        【讨论】:

          【解决方案6】:

          1) 这是 C++ 的一个特性,函数 try-catch 块(例如,参见 here
          2) 是的,catch(...) { /* absolutely any exception gets caught here */ }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-08-27
            • 2016-06-04
            • 1970-01-01
            • 2021-12-13
            • 2014-05-31
            • 2018-03-01
            • 2016-04-21
            相关资源
            最近更新 更多