问题
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?
回答1:
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.
回答2:
Do it like this:
template <typename T> constexpr
auto myfunc() noexcept(std::is_nothrow_default_constructible_v<T>)
{
return T{};
}
来源:https://stackoverflow.com/questions/49957330/copy-elision-of-return-values-and-noexcept