Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

copy elision of return values and noexcept

Tags:

I have a function template like this:

template <typename T>
constexpr auto myfunc() noexcept
{
    return T{};
}

Is this function template guaranteed to be noexcept because of copy elision? If an exception is thrown inside the constructor, does this happen inside or outside the function?

like image 847
Martin Fehrs Avatar asked Apr 21 '18 15:04

Martin Fehrs


People also ask

How does copy elision work?

Copy elision is the general process where, when returned from a function, an object is not copied nor moved, resulting in zero-copy pass-by-value semantics. It includes both return value optimization (RVO) and named return value optimization (NRVO).

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).

What is NRVO?

This particular technique was later coined "Named return value optimization" (NRVO), referring to the fact that the copying of a named object is elided.

What are copy constructors in C++?

Copy Constructor in C++ A copy constructor is a member function that initializes an object using another object of the same class. In simple terms, a constructor which creates an object by initializing it with an object of the same class, which has been created previously is known as a copy constructor.


1 Answers

All that copy elision does is eliminate the actual copy or move. Everything happens "as-if" things happen without the copy-elision taking place (except for the copy itself, of course).

The construction occurs inside the function. Copy elision does not change that. All it does is eliminate the actual copy/move from taking place (am I repeating myself?) as the result of the function's return value getting shoved back into its caller.

So, if the class's default constructor throws an exception, the noexcept nukes the whole thing from high orbit.

If the copy/move constructor throws an exception, since the copy/move does not happen, everything continues to chug along.

With gcc 7.3.1, compiled using -std=c++17:

template <typename T>
constexpr auto myfunc() noexcept
{
    return T{};
}

class xx {
public:

    xx() { throw "Foo"; }
};

int main()
{
    try {
        myfunc<xx>();
    } catch (...) {
    }
}

The result:

terminate called after throwing an instance of 'char const*'

Now, let's mix it up, and throw an exception in both copy and move constructors:

class xx {
public:

    xx() { }

    xx(xx &&) { throw "Foo"; }

    xx(const xx &) { throw "Baz"; }
};

This runs without an exception.

like image 145
Sam Varshavchik Avatar answered Oct 11 '22 15:10

Sam Varshavchik