How to simulate inner exception in C++

前端 未结 6 1561
逝去的感伤
逝去的感伤 2021-01-02 19:06

Basically I want to simulate .NET Exception.InnerException in C++. I want to catch exception from bottom layer and wrap it with another exception and throw again to upper la

相关标签:
6条回答
  • 2021-01-02 19:12

    Since C++ 11 you have new options:

    1. You can use std::exception_ptr.

      The exception is then preserve until last exception_ptr to this exception is destroyed.

      struct base_exception : public std::exception
      {
          std::exception_ptr InnerException;
      
          base_exception() {}
          base_exception(std::exception& innerException)
           : InnerException(std::make_exception_ptr(innerException))
          {}
      
      };
      
    2. Or you can simply use std::nested_exception.
    0 讨论(0)
  • 2021-01-02 19:23

    Also I am not sure whether the temporary object that is thrown from func1 will survive even after func2 throw?

    No. Unless you rethrow the exception with throw;. You could implement this if you'd allow only some (limited) set of exception types.

    0 讨论(0)
  • 2021-01-02 19:26
    //inversion of the problem :)
    struct base_exception : public std::exception
    {
        std::list<base_exception*> snowball;
    
        base_exception() { }
        void add(base_exception* e) { snowball.push_back(e); }
    };
    
    void func2()
    {
        func2_exception e;
        e.add(new func2_exception());
        throw e;
    }
    
    void func1()
    {
        try
        {
            func2();
        }
        catch(base_exception& e)
        {
            e.add(new func1_exception());
            throw e; 
        }
    }
    int main(void)
    {
        try
        {
            func1();
        }
        catch(base_exception& e)
        {
            std::cout << "Got exception" << std::endl;
            //print info in the direct order of exceptions occurence
            foreach(base_exception* exception, e.snowball)
            {
                  std::cout << exception->what();
                  std::cout << "next exception was:" << std::endl;
            }
        }
    }
    

    hmmmm...

    0 讨论(0)
  • 2021-01-02 19:27

    One problem with the inner exception is the possibility to throw it again while maintaining polymorphic behaviour.

    This can be (somewhat) alleviate by actually managing the exception lifetime yourself and providing polymorphic copies.

    // Base class
    class exception: virtual public std::exception, private boost::noncopyable
    {
    public:
      virtual exception* clone() const = 0;
      virtual void rethrow() const = 0; // throw most Derived copy
    };
    
    // ExceptionPointer
    class ExceptionPointer: virtual public std::exception
    {
    public:
      typedef std::unique_ptr<exception> pointer;
    
      ExceptionPointer(): mPointer() {}
      ExceptionPointer(exception* p): mPointer(p) {}
      ExceptionPointer(pointer p): mPointer(p) {}
    
      exception* get() const { return mPointer.get(); }
      void throwInner() const { if (mPointer.get()) mPointer->rethrow(); }
    
      virtual char* what() const { return mPointer.get() ? mPointer->what() : 0; }
    
    private:
      pointer mPointer;
    };
    

    How to use ?

    try
    {
      // some code
    }
    catch(exception& e)
    {
      throw ExceptionPointer(e.clone());
    }
    
    // later on
    try
    {
    }
    catch(ExceptionPointer& e)
    {
      e.throwInner();
    }
    
    0 讨论(0)
  • 2021-01-02 19:31

    You should also take a look at boost exception for an alternative solution to wrapping.

    0 讨论(0)
  • 2021-01-02 19:37

    As stated by others, boost::exception is a nice option. However, like all options that use a common base class approach, they rely on all thrown exceptions being derived from that base class. If your intermediary catch handlers need to add information to an exception from a third party library it won't work.

    An option that might be sufficient is to have intermediary catch handlers like this:

    catch (std::exception& ex)
    {
       std::string msg = ex.what();
       msg.append(" - my extra info");
       ex = std::exception(msg.c_str()); // slicing assignment
       throw;                            // re-throws 'ex', preserving it's original type
    }
    

    This only works for implementations of std::exception that provide a constructor taking a string parameter (e.g. VC++). The std::exception constructor taking a string is a non-standard extension.

    0 讨论(0)
提交回复
热议问题