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?
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).
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).
This particular technique was later coined "Named return value optimization" (NRVO), referring to the fact that the copying of a named object is elided.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With