为何C++异常处理中拷贝消除未生效?GCC 7.2测试疑问
Great question! Let's break down why you're still seeing a copy constructor call even though it seems like cppreference's copy elision rule should apply here.
First, let's recap the rule you referenced:
处理异常时,若catch子句的参数与抛出的异常对象类型(忽略顶层cv限定符)相同,则可省略拷贝,直接访问异常对象,如同按引用捕获。
Key Point 1: This Is an Optional Optimization, Not a Requirement
The C++ standard permits compilers to perform this copy elision, but it does not force them to implement it. Compiler vendors make choices based on factors like implementation complexity, debugging usability, and exception safety tradeoffs. This means even if your code meets the criteria, the compiler might still skip the optimization.
Key Point 2: GCC 7.2 Doesn't Implement This Optimization by Default
In your case, GCC 7.2 (and many older GCC versions) deliberately chooses not to elide the copy when catching exceptions by value—even when the type matches exactly. The compiler maintains separate storage for the exception object and the catch parameter, so a copy is made between them.
Even with -O2 enabled, this specific optimization isn't applied in GCC's exception handling pipeline. Newer GCC versions have improved some optimizations, but this elision still isn't universally supported for catch clauses.
How to Avoid the Copy Reliably
If you want to eliminate the copy entirely (also a best practice for exception handling), switch to catching by reference instead:
catch(const Exception& e) { }
This lets you directly reference the exception object stored in the exception handling area—no copy is made, and you also avoid potential slicing issues if you ever extend your Exception class.
Quick Breakdown of Your Output
Your current output:
constructed copy constructed
- The first line comes from constructing the temporary
Exception()inthrow Exception()—the compiler does elide the copy from this temporary to the exception storage area (so you don't see an extra copy/move here). - The second line is the copy from the exception storage area to your catch parameter
e—this is the copy GCC isn't eliding.
内容的提问来源于stack exchange,提问作者Pumkko

