What type of exception should I throw?

后端 未结 5 1181
难免孤独
难免孤独 2020-12-08 03:40

After going through some links on exception handling (1, 2, and 3), I know that C++ programs can throw pretty much anything as exceptions (int, char*

5条回答
  •  误落风尘
    2020-12-08 04:16

    If you can use boost then you should do so. Refer to this link on how to use boost exceptions. You can also design your own exception class hierarchy as stated by other answers, but you need to take care of subtle aspects like 'nothrow' requirements from the 'what' method. A basic design on how this can be done on the lines of boost::exception is explained below:-

    #include 
    #include 
    #include 
    
    /************************************************************************/
    /* The exception hierarchy is devised into 2 basic layers. 
       System exceptions and Logic exceptions. But Logic exceptions are 
       convertible to the ultimate base 'System' in the system layer.
    *************************************************************************/
    
    // the system exception layer
      namespace ExH
      {
        namespace System {
          // This is the only way to make predefined exceptions like
          // std::bad_alloc, etc to appear in the right place of the hierarchy.
          typedef std::exception Exception;
          // we extend the base exception class for polymorphic throw
          class BaseException : public Exception {
          public:
            BaseException() throw() {}
            explicit BaseException(char const* /*desc*/) throw() 
              : Exception()
            {}
            BaseException(BaseException const& that)
              : Exception(that)
            {}
            virtual void raise() const { throw *this; } // used to throw polymorphically
            virtual ~BaseException() throw () {}
          };
          // module level classes compose and catch the descriptive
          // versions of layer-exceptions
          class DescriptiveException : public BaseException  {
          public:
            explicit DescriptiveException (char const* description) throw()
              : description_(description)
            { }
            explicit DescriptiveException (std::string const& description) throw()
              : description_(description.c_str())
            { }
    
            virtual ~DescriptiveException () throw () {} 
    
            DescriptiveException (DescriptiveException const& src) throw()
              : BaseException(src)
            {
              this->description_ = src.description_;
            }
            DescriptiveException& operator= (DescriptiveException const& src) throw()
            {
                if (this != &src)
                {
                  this->description_ = src.description_;
                }
                return *this;
            }
    
            /*virtual*/ char const* what () const throw() { return description_; }
            /*virtual*/ void raise() const // used to throw polymorphically
            { throw *this; }
          protected:
            DescriptiveException () throw ();
          private:
            char const* description_; 
          };
    
        }
      }
    
    // the logic exception layer
      namespace ExH
      {
        namespace Logic
        {
    
          // Logic::Exception inherits from System::Exception for the
          // following reason. Semantically for some part of the
          // system particular instance of Logic::Exception may seem as
          // opaque System::Exception and the only way to handle it would
          // be to propagate it further. In other words Logic::Exception
          // can be seamlessly "converted" to System::Exception if there is
          // no part of the system interested in handling it.
          //
          class BaseException : public System::BaseException
          {
          public:
            BaseException() throw() {}
            explicit BaseException(char const* desc) throw() 
              : System::BaseException(desc)
            {}
            BaseException(BaseException const& that)
              : System::BaseException(that)
            {}
            virtual void raise() const { throw *this; } // used to throw polymorphically
            virtual ~BaseException() throw () {}
          };
          // module level classes compose and catch the descriptive
          // versions of layer-exceptions
          class DescriptiveException : public BaseException {
          public:
            explicit
            DescriptiveException (char const* description) throw()
              : description_(new std::string(description))
            { }
            explicit
            DescriptiveException (std::string const& description) throw()
              : description_(new std::string(description))
            { }
            DescriptiveException(DescriptiveException const& src) throw()
              : BaseException(src)
            {
                // copy the string
                std::string* str = new std::string(src.description_.get()->c_str());
                description_.reset(str);
            }
    
            virtual ~DescriptiveException () throw () {}
            /*virtual*/ char const* what () const throw() { return description_->c_str(); }
            /*virtual*/ void raise() const { throw *this; }
          private:
            DescriptiveException& operator= (DescriptiveException const& src) throw(); // copy disabled
            std::auto_ptr description_; // do not use std::string, as it can throw
          };
        }
      }
    
    
    /************************************************************************/
    /* Users of the exception hierarchy compose specific exceptions as and
    when needed. But they can always be caught at the System::Exception base
    class level. Some of the standard conversion examples are demonstrated :-
    
    class MyClass {
    public:
      class Exception_ {};
      typedef
      Compound 
      Exception;
    
      class InvalidArgument_ {};
      typedef
      Compound 
      InvalidArgument;
    
      class NotInitialized_ {};
      typedef
      Compound 
      NotInitialized;
    public:
      void myFunction1() const throw(NotInitialized);
      void myFunctionN() const throw(NotInitialized);
    };
    
    void MyClass::myFunction1() const {
      throw NotInitialized("Not Inited!");
    }
    
    void MyClass::myFunctionN() const {
      try {
        // call myFunction1()
      }
      catch(NotInitialized const& e){
      // use e
      }
    }
    
    This has to be per-class basis. The exposed module will have an exception
    specification which will catch all the sub-class exceptions. The calling
    module will in turn rely on this exception-specification. This will allow
    us to have generalized exception-catching at the application-level and
    more specialized exception-catching at the specific module level.       */
    /************************************************************************/
    
    // a simple template to compose the exceptions as per conversion requirements
      namespace ExH
      {
        template 
        class Compound : public Base
        {
        public:
          explicit Compound (char const* description) throw ()
            : Base(description)
          {}
          explicit Compound (std::string const& description) throw ()
            : Base(description)
          {}
    
          Compound (Compound const& src) throw ()
            : Base(src)
          {}
    
          virtual ~Compound () throw () {}
        protected:
          Compound () throw () {}
        private:
          Compound& operator= (Compound const& src) throw (); // disable copy
        };
    
      }
    

提交回复
热议问题