Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this quote from cppreference.com about implicit throw from a destructor a typo?

Tags:

c++

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.

like image 466
shawn1874 Avatar asked Jul 29 '26 10:07

shawn1874


1 Answers

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';
   }
}
like image 193
shawn1874 Avatar answered Jul 31 '26 00:07

shawn1874



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!