函数 try catch 语法和 main

发布于 2024-12-19 23:51:05 字数 790 浏览 1 评论 0原文

一个鲜为人知但几乎从未使用过的 C++ 功能给出了一个声明:

void foo();

一个可能的合法定义可能是:

void foo() try {
  throw 42;
}
catch(...) {
}

这里 整个函数实现包装在 try/catch内,这似乎类似于允许 这个

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

int main() try {
  throw 42;
}
catch(...) {
}

main 的规则,n3290 § 3.6.1 主要是谈论关于它应该采用什么参数以及它返回什么 - 他们似乎没有明确禁止它,就像他们对您可能想尝试的各种其他奇怪的事情(例如链接)所做的那样。

这是合法且明确定义的吗?

A little known, but almost never used C++ feature is given a declaration:

void foo();

One possible, legal definition could be:

void foo() try {
  throw 42;
}
catch(...) {
}

Here the whole function implementation wrapped is within a try/catch pair, which seems to be similar to allowing this.

Is that legal to do for int main()? E.g.:

int main() try {
  throw 42;
}
catch(...) {
}

The rules for main, n3290 § 3.6.1 mostly talk about what arguments it should take and what it returns - they don't seem to explicitly forbid it as they do with various other odd things (e.g. linkages) you might be tempted to try.

Is this legal and well defined?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪菊怪哟 2024-12-26 23:51:05

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

单独来看,它至少看起来是合法的,尽管当然这只涉及函数声明,而不涉及函数定义。

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

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

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

我在这个答案的第一个版本中提供的博客文章实际上很好地说明了上述块引用给出的规则,所以我'将保留指向它的链接,即使它不直接在中讨论该问题OP的问题。

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

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

如果您位于 main 末尾的 catch 块中,则不会流过函数体(在本例中为 try 块) ),因此 main 在溢出时自动调用 return 0; 的规则不适用。您需要返回一些int(很可能是错误代码)以防止变得未定义。

The standard does not forbid its usage within [basic.start.main], and, while forcing all implementations to support at least int main() {/*...*/ } and int main(int argc, char* argv[]) {/*...*/}, does not limit implementations to those two declarations (3.6.1, para. 2).

From that in isolation, it would appear at the least that it is legal, though of course that relates only to function-declarations, not function-definitions.

Reading on, [except.handle], paragraph 13 states the following:

Exceptions thrown in destructors of objects with static storage
duration or in constructors of namespace-scope objects are not caught
by a function-try-block on main(). (15.3 para. 13)

It makes specific mention of a function-try-block placed on main(), which strongly implies that such a structure is legal and has defined behavior. Adding in the information that main() is only special in its name and return type, and that implementations may not overload it to alter any behavior, makes a pretty strong case that it acts in a normal fashion except when specially noted such as in the above quote. In other words, yes, it is legal and well-defined.

The blog post I supplied in the first version of this answer actually does a good job of illustrating the rules given by the above blockquote, so I'll retain the link to it, even though it does not directly discuss the issue in the OP's question.

Regarding a comment on the OP, you can issue return statements within a function-try-block, and [except.handle] has this to say:

Flowing off the end of a function-try-block is equivalent to a return
with no value; this results in undefined behavior in a value-returning
function (6.6.3). (15.3 para. 15)

If you're in a catch-block at the end of main, you're not going to flow over the function's body (which would be the try-block in this case), so the rule that main automatically calls return 0; on flowover doesn't apply. You need to return some int (quite possibly an error code) to keep from becoming undefined.

黯淡〆 2024-12-26 23:51:05

我已经尝试过,它可以编译,并且可以按预期运行。这是一个奇怪的表述,但我不认为它违反了任何规则。
为了清楚起见(为了您自己和未来的代码维护人员),您还可以将其重新表述为:

int main() 
{
    try {
      throw 42;
    }
    catch( int /*...*/) {
    }
}

I have tried it, it compiles, and it runs as expected. A peculiar formulation, but I don't think it breaks any rules.
For clarity (for yourself and future code mantainers), you could also rephrase it as:

int main() 
{
    try {
      throw 42;
    }
    catch( int /*...*/) {
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文