catch 语句中可以发生复制省略吗?

发布于 2024-12-04 08:19:02 字数 454 浏览 2 评论 0原文

考虑一个带有带有副作用的复制构造函数的异常类。

编译器可以跳过在这里调用复制构造函数吗:

try {
    throw ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }

这个怎么样:(

try {
    something_that_throws_ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }

是的,我知道这一切都非常丑陋,这是受到 另一个问题)

Consider an exception class with a copy constructor with side-effects.

Can a compiler skip calling the copy constructor here:

try {
    throw ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }

What about this:

try {
    something_that_throws_ugly_exception();
}
catch(ugly_exception) // ignoring the exception, so I'm not naming it
{ }

(yes, I know this is all very ugly, this was inspired by another question)

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

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

发布评论

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

评论(3

橙味迷妹 2024-12-11 08:19:03

我认为这是特别允许的。对于 C++03,15.1/3 说:

抛出表达式初始化一个临时对象,称为
异常对象,

12/15 说:

当尚未绑定到引用的临时类对象时
(12.2) 将被复制到具有相同 cv-unqualified 的类对象
类型,可以通过构造 tempo- 来省略复制操作
rary对象直接进入省略复制的目标

秘密隐藏位置由标准定义为临时的,因此对于复制省略是有效的。

编辑:哎呀,我现在已经进一步阅读了。 15.1/5:

如果临时对象的使用可以消除而不改变
除了构造函数的执行之外的程序的含义
和与临时对象的使用相关的析构函数
(12.2),那么handler中的异常可以直接初始化
与 throw 表达式的参数一起。

并没有变得更清楚。

无论它实际上是否会...如果 catch 子句要重新引发异常(包括它调用可能这样做的不可见代码),那么实现需要“称为异常对象的临时对象”仍然存在。因此,何时可以进行复制省略可能会受到一些限制。显然,空的 catch 子句不能重新引发它。

I think this is specifically permitted. For C++03, 15.1/3 says:

A throw-expression initializes a temporary object, called the
exception object,

and 12/15 says:

when a temporary class object that has not been bound to a reference
(12.2) would be copied to a class object with the same cv-unqualified
type, the copy operation can be omitted by constructing the tempo-
rary object directly into the target of the omitted copy

So, the secret hiding place where in-flight exceptions are kept, is defined by the standard to be a temporary, and hence is valid for copy-elision.

Edit: oops, I've now read further. 15.1/5:

If the use of the temporary object can be eliminated without changing
the meaning of the program except for the execution of constructors
and destructors associated with the use of the temporary object
(12.2), then the exception in the handler can be initialized directly
with the argument of the throw expression.

Doesn't get much clearer.

Whether it actually will... if the catch clause were to re-raise the exception (including if it called non-visible code that might do so), then the implementation needs that "temporary object called the exception object" still to be around. So there might be some restrictions on when that copy elision is possible. Clearly an empty catch clause can't re-raise it, though.

滴情不沾 2024-12-11 08:19:03

是的。如果catch通过引用捕获异常,那么就不会存在复制(嗯,这是根据定义)。

但我认为这不是你的问题,而且我相信你编写的代码是故意编写的,没有提及引用。如果是这样的话,那么是的,即使在这种情况下,副本也可以被省略。实际上,catch 中变量的初始化理论上是直接初始化。如果可能的话,编译器可以省略直接初始化中的复制。

C++03 §8.5/14 读取,

[...]在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除直接初始化中固有的复制;

Yes. If the catch catches the exception by reference, then there will not be copy (well, that is by definition).

But I think that is not your question, and I believe the code which you've written is written on purpose with no mention of reference. If that is the case, then yes, even in this case, copy can be elided. Actually initialization of the variable in the catch is direct-initialization in theory. And copy in a direct-initialization can be elided by the compiler where it's possible.

C++03 §8.5/14 reads,

[...] In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized;

Saygoodbye 2024-12-11 08:19:02

是的,在投掷和接球过程中都可以忽略它。对于捕获,只有当 catch 子句中指定的类型与异常对象的类型相同(除了 cv 限定)时,才可以忽略它。有关更正式和详细的描述,请参阅 C++11 12.8/31。

...这种复制/移动操作的省略称为复制省略,在以下情况下是允许的(可以组合起来消除多个副本):

...

  • 在 throw 表达式中,当操作数是非易失性自动对象(函数或 catch 子句参数除外)的名称时,其范围不会超出最内层封闭 try 块的末尾(如果有一个),通过将自动对象直接构造到异常对象中,可以省略从操作数到异常对象(15.1)的复制/移动操作

...

  • 当异常处理程序的异常声明(第 15 条)声明与异常对象(15.1)相同类型(cv 限定除外)的对象时,可以通过处理异常来省略复制/移动操作- 声明作为异常对象的别名,如果除了执行由异常声明声明的对象的构造函数和析构函数之外,程序的含义将保持不变。

Yes, it can be elided both during throwing and catching. For catching it can be elided only when the type specified in the catch clause is the same (save for cv-qualifications) as the type of the exception object. For more formal and detailed description see C++11 12.8/31.

...This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

...

  • in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object (15.1) can be omitted by constructing the automatic object directly into the exception object

...

  • when the exception-declaration of an exception handler (Clause 15) declares an object of the same type (except for cv-qualification) as the exception object (15.1), the copy/move operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文