函数 try catch 语法和 main

Posted

技术标签:

【中文标题】函数 try catch 语法和 main【英文标题】:function try catch syntax and main 【发布时间】:2012-01-14 09:04:57 【问题描述】:

一个鲜为人知但几乎从未使用过的 C++ 特性被声明:

void foo();

一种可能的法律定义是:

void foo() try 
  throw 42;

catch(...) 

这里是whole function implementation wrapped is within a try/catch pair,似乎类似于允许this。

int main() 这样做合法吗?例如:

int main() try 
  throw 42;

catch(...) 

The rules for main, n3290 § 3.6.1 主要谈论它应该采用什么参数以及它返回什么 - 他们似乎没有像处理其他各种奇怪的事情(例如链接)那样明确禁止它,你可能会受到诱惑试试看。

这是否合法且定义明确?

【问题讨论】:

有趣的学术问题,虽然我不确定它有多少实际用途。 ***.com/a/620817/10077 合法吗?从技术上讲,大多数编译器都会支持它。定义好?不是真的,因为我当然想不出任何理智的理由这样做。 @AJG85 - 我的意思是在“既不调用未定义的行为,也不调用实现定义的行为”的意义上定义良好,而不是以“在常见实现中经过良好测试”的方式 @awoodland:在那种情况下,正如您所指出的那样,标准并没有说太多。它将留给编译器实现,因此会有很大差异。 @AJG85 - 如果它留给编译器,那么它是实现定义的,并将在标准后面的“实现定义的行为索引”中。 【参考方案1】:

该标准并未禁止在 [basic.start.main] 中使用它,并且虽然强制所有实现至少支持 int main() /*...*/ int main(int argc, char* argv[]) /*...*/,但并不将实现限制为这两个声明 (3.6.1,第 2 段)。

从孤立的角度来看,它至少看起来是合法的,尽管它当然只与函数声明有关,而不是函数定义。

继续阅读,[except.handle],第 13 段陈述如下:

静态存储对象的析构函数中抛出的异常 持续时间或命名空间范围对象的构造函数没有被捕获 通过 main() 上的函数尝试块。 (15.3 第 13 段)

它特别提到了一个放在main() 上的function-try-block,这强烈暗示这种结构是合法的并且具有定义的行为。添加 main() 仅在其名称和返回类型上是特殊的信息,并且实现可能不会重载它以改变任何行为,这使得它以正常方式运行的一个非常有力的案例,除非特别指出,例如在以上报价。换句话说,是的,它是合法的且定义明确的。

我在这个答案的第一个版本中提供的博客文章实际上很好地说明了上述块引用给出的规则,所以我会 retain the link to it,即使它没有直接讨论 OP 中的问题问题。

关于 OP 的评论,您可以在 function-try-block 中发出 return 语句,[except.handle] 有这样的说法:

从函数尝试块的末尾流出等同于返回 没有价值;这会导致值返回中的未定义行为 功能(6.6.3)。 (15.3 第 15 段)

如果你在 main 末尾的一个 catch-block 中,你就不会流过函数的主体(在这种情况下是 try 块),所以 main 自动的规则在溢出时调用return 0; 不适用。您需要返回一些 int(很可能是错误代码)以防止变得未定义。

【讨论】:

没有太多信息(关于定义),static 状态相当简单:“全局”对象在 main 被调用之前被初始化并在它返回后被销毁......所以显然不是在try/catch 块内。至于对构造函数语法的评论,是的,这很奇怪,但也没有真正回答这个问题...... 我同意该评估,并已注意到;谢谢。我发现一个明确的参考 main() 有功能尝试块,所以我认为这篇文章无论如何都没有用。我将进行编辑以澄清这一点。 15.3 中的那句话非常有趣。 (如果它是合法的,那可能是我的下一个问题)结合约翰内斯链接到的 DR 似乎可以回答它。 删除我的答案..需要在家进行调查...但是如果不暗示所有其他定义,那么给出两种必需的 main 定义形式有什么意义表单不需要工作吗? 从 c++11 开始,函数tryblock 函数体:-)【参考方案2】:

我已经尝试过了,它可以编译,并且可以按预期运行。一个特殊的表述,但我认为它没有违反任何规则。 为清楚起见(对于您自己和未来的代码维护者),您还可以将其改写为:

int main() 

    try 
      throw 42;
    
    catch( int /*...*/) 
    

【讨论】:

它也适用于我的编译器。 “它编译并运行”的问题是我知道我的编译器编译并运行了很多没有明确定义的东西。 公平点,@awoodland。因此,有疑问,我建议使用我上面提到的公式,这似乎完全符合您的要求。不过,您最初的表述似乎并没有违反标准中的任何规则。

以上是关于函数 try catch 语法和 main的主要内容,如果未能解决你的问题,请参考以下文章

带有 try catch 的 PDO 事务语法

函数try{}

Java编程trycatch的语法使用格式

Sql语法高级应用之六:如何在Sql语句中如何使用TRY...CATCH

php 语法错误定位 try catch Throwable

java的5种异常的语法