Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy elision and exceptions

After reading about copy elision of cppreference I wanted to play with exceptions and copy elision. So I wrote the following code with gcc 7.2 on coliru

#include <iostream>

class Exception
{
public:
    Exception() { std::cout << "constructed\n"; }
    Exception(Exception& other) {std::cout << "copy constructed\n";}
    Exception(const Exception& other) {std::cout << "copy constructed\n";}
    Exception(Exception&& other) {std::cout << "move constructed\n";}
};

void foo()
{
    throw Exception();
}

int main()
{
    try
    {
        foo();
    }
    catch(Exception e )
    {

    }
}

Output

constructed
copy constructed

We can see that the copy constructor is called and this happens even when gcc is invoked with -O2. It seems to me that this code should be eligible to copy elision according to the following clause :

When handling an exception, if the argument of the catch clause is of the same type (ignoring top-level cv-qualification) as the exception object thrown, the copy is omitted and the body of the catch clause accesses the exception object directly, as if caught by reference.

So why is the copy constructor called? Why does copy elision not work in this case?

like image 506
Pumkko Avatar asked Jan 15 '18 08:01

Pumkko


People also ask

What is copy elision in Javascript?

Copy elision is an optimization implemented by most compilers to prevent extra (potentially expensive) copies in certain situations. It makes returning by value or pass-by-value feasible in practice (restrictions apply).

Is copy elision guaranteed?

Copy elision (NRVO) is allowed there and is routinely performed by most compilers, but is still non-guaranteed, and the widget class cannot be non-copyable non-movable.

What is elision programming?

It is in this sense that computer language designers have borrowed the term: an elision in a programming language is when the language makes optional what might be thought of as a necessary portion of the grammar.

What is RVO CPP?

In the context of the C++ programming language, return value optimization (RVO) is a compiler optimization that involves eliminating the temporary object created to hold a function's return value. RVO is allowed to change the observable behaviour of the resulting program by the C++ standard.


1 Answers

cppreference is inaccurate on this. There is in fact no guarantee that the copy will be elided except in a constant expression (constexpr) or a constant initialization (static or thread-local). That is not the case in your example.

See [class.copy.elision]/1 in the current C++17 draft (emphasis mine):

When certain criteria are met, ... elision of copy/move operations, called copy elision, is permitted in the following circumstances:

— 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 can be omitted by constructing the automatic object directly into the exception object

Copy elision is required where an expression is evaluated in a context requiring a constant expression and in constant initialization.

That means that some day it may be implemented as a compiler optimization, it is just not the case currently.

It would be wise therefore to catch by const& for the time being (also to avoid accidental slicing).

like image 121
rustyx Avatar answered Oct 20 '22 05:10

rustyx