right usage of std::uncaught_exception in a destructor

后端 未结 3 2029
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-05 05:06

There are some articles concluding \"never throw an exception from a destructor\", and \"std::uncaught_exception() is not useful\", for example:

  • http://www.got
3条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-01-05 05:18

    Herb Sutter is talking about the situation when an object of class T is destroyed while there is an uncaught exception in an object of class U. std::uncaught_exception() would return true in the T destructor. The destructor would be unable to find out whether it's called during stack unwinding. If it is, it must not throw, otherwise it's business as usual.

    The class U would have a problem using class T in the destructor. U would find itself dealing with a useless T object that would refuse to do anything risky in its destructor (that could include writing a log file or committing a transaction to a database).

    Herb Sutter suggests never throwing in a destructor, which is a good idea. However, the C++17 offers another option. It introduced std::uncaught_exceptions(), which can be used to find out whether the destructor can throw. Following example shows the problem if complied in C++14 mode. If compiled in C++17 mode, it would work correctly.

    
    #include 
    #include 
    #include 
    
    class T
    {
      public:
    
        ~T() noexcept(false)
        {
    #if __cplusplus >= 201703L
          // C++17 - correct check
          if (std::uncaught_exceptions() == uncaught_exceptions_)
    #else
          // Older C++ - incorrect check
          if (!std::uncaught_exception())
    #endif
          {
            throw (std::string{__PRETTY_FUNCTION__} + " doing real work");
          }
          else
          {
            std::cerr << __PRETTY_FUNCTION__ << " cowardly quitting\n";
          }
        }
    
      private:
    
    #if __cplusplus >= 201703L
        const int uncaught_exceptions_ {std::uncaught_exceptions()};
    #endif
    };
    
    class U
    {
      public:
    
        ~U()
        {
          try
          {
            T t;
          }
          catch (const std::string &e)
          {
            std::cerr << __PRETTY_FUNCTION__ << " caught: " << e << '\n';
          }
        }
    };
    
    int main()
    {
      try
      {
        U u;
        throw (std::string{__PRETTY_FUNCTION__} + " threw an exception");
      }
      catch (const std::string &e)
      {
        std::cerr << __PRETTY_FUNCTION__ << " caught: " << e << '\n';
      }
      return 0;
    }
    

提交回复
热议问题