Does this quote from https://en.cppreference.com/w/cpp/language/function-try-block have a typo?
Reaching the end of a catch clause for a function-try-block on a destructor also automatically rethrows the current exception as if by
throw;, but a return statement is allowed.
It seems hard to believe that a destructor automatically re-throws, when every article by every expert I've ever read says that destructors should never, ever throw under any circumstance. In fact, the example code above the quote shows an implicit throw from a constructor, not a destructor.
Therefore, I wonder, is the statement wrong and should have indicated that behavior for a constructor instead?
I had been reviewing this other StackOverflow article when I started thinking about this: C4297 warning in Visual Studio while using function-try-block (function assumed not to throw an exception but does). It already had an answer, but nobody questioned whether the quote was accurate in the first place.
The answer is no, it is not a typo.
The cppreference article did not show an example of a destructor function try block, so I crafted one myself and tested it. Below is the same code. I tested with Microsoft VS2019, using the v142 platform toolset and C++20 dialect.
If you execute this, an abort will be called, which is consistent with the warning that the compiler issues. This suggests that the function catch block does automatically re-throw, even for a destructor. If you uncomment the return statement, it will not throw. Although, I find that to be counter-intuitive, writing a return statement provides a workaround to prevent the implicit throw, just as the referenced StackOverflow article suggests.
#include <iostream>
#include <string>
struct S
{
std::string m;
S(const std::string& str, int idx) try : m(str, idx)
{
std::cout << "S(" << str << ", " << idx << ") constructed, m = " << m << '\n';
}
catch (const std::exception& e)
{
std::cout << "S(" << str << ", " << idx << ") failed: " << e.what() << '\n';
} // implicit "throw;" here
~S() try
{
if (m.length() > 5) {
throw std::exception("shouldn't have been that big!");
}
std::cout << "destroyed!" << std::endl;
}
catch (const std::exception& e)
{
//return;
}
};
int main()
{
S s1{ "ABC", 1 }; // does not throw (index is in bounds)
try
{
S s2{ "ABC", 4 }; // throws (out of bounds)
}
catch (std::exception& e)
{
std::cout << "S s2... raised an exception: " << e.what() << '\n';
}
try
{
S s3("123456", 0);
}
catch (std::exception& e)
{
std::cout << "S s2... raised an exception: " << e.what() << '\n';
}
}
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