Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Strategy of handling errors in C++
Forum Updated to NodeBB v4.3 + New Features

Strategy of handling errors in C++

Scheduled Pinned Locked Moved C++ Gurus
11 Posts 6 Posters 6.2k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • 8Observer88 Offline
    8Observer88 Offline
    8Observer8
    wrote on last edited by
    #1

    Hi

    Please talk me about your strategy of handling errors

    What do you think about this?

    main.cpp
    [CODE]
    #include <iostream>
    #include "Calculator.h"

    int main()
    {
    Calculator<float> calculator;

    try {
        float result = calculator.divide( 24.7f, 3.0f );
        std::cout << "Result = " << result << std::endl;
    } catch ( const LogicError &e ) {
        std::cerr << e.what() << std::endl;
        return 1;
    } catch ( ... ) {
        std::cerr << "Error: unknown expection" << std::endl;
        return 1;
    }
    
    return 0;
    

    }[/CODE]

    Calculator.h
    [CODE]
    #ifndef CALCULATOR_H
    #define CALCULATOR_H

    #include <string>
    #include "DivideByZero.h"
    #include "OutOfRange.h"

    template <typename Type>
    class Calculator
    {
    public:
    // Divide nums from the range [-1000, 1000]
    Type divide( Type a, Type b )
    throw ( DivideByZero, OutOfRange<int> )
    {
    std::string functionName = "Calculator::divide()";
    if ( b == 0 ) {
    throw DivideByZero( functionName );
    }

        const int beginOfRange = -1000;
        const int endOfRange = 1000;
    
        if ( ( a < beginOfRange ) || ( a > endOfRange ) ||
             ( b < beginOfRange ) || ( b > endOfRange ) )
        {
            throw OutOfRange<int>( beginOfRange,
                                   endOfRange,
                                   functionName );
        }
    
        return a / b;
    }
    

    };

    #endif // CALCULATOR_H[/CODE]

    DivideByZero.h
    [CODE]
    #ifndef DIVIDEBYZERO_H
    #define DIVIDEBYZERO_H

    #include <string>
    #include "LogicError.h"

    class DivideByZero : public LogicError
    {
    public:
    DivideByZero( const std::string &functionName ) :
    LogicError( functionName )
    {
    m_message = "Error: divide by zero in the "
    "function " + m_functionName;
    }
    };

    #endif // DIVIDEBYZERO_H[/CODE]

    OutOfRange.h
    [CODE]
    #ifndef OUTOFRANGE_H
    #define OUTOFRANGE_H

    #include <string>
    #include "LogicError.h"

    template <typename Type>
    class OutOfRange : public LogicError
    {
    public:
    OutOfRange( Type beginOfRange,
    Type endOfRange,
    const std::string &functionName ) :
    LogicError( functionName )
    {
    m_message = "Error: values must be from the range "
    "[" + std::to_string( beginOfRange ) +
    ", " + std::to_string( endOfRange ) + "]"
    " in the function " + m_functionName;
    }
    };

    #endif // OUTOFRANGE_H[/CODE]

    LogicError.h
    [CODE]
    #ifndef LOGICERROR_H
    #define LOGICERROR_H

    #include <string>
    #include <stdexcept>

    class LogicError : public std::logic_error
    {
    public:

    LogicError( const std::string &functionName ) :
        std::logic_error( "" ),
        m_functionName( functionName ),
        m_message( "" )
    {
    
    }
    
    virtual ~LogicError( ) throw( )
    {
    
    }
    
    virtual const char *what( ) const throw( )
    {
        return m_message.c_str( );
    }
    
    std::string message( ) const
    {
        return m_message;
    }
    

    protected:
    std::string m_functionName;
    std::string m_message;
    };

    #endif // LOGICERROR_H[/CODE]

    ? 1 Reply Last reply
    0
    • 8Observer88 Offline
      8Observer88 Offline
      8Observer8
      wrote on last edited by
      #2

      This is Qt example. It is about reading/writing file

      main.cpp
      [code]
      #include <iostream>
      #include <vector>
      #include <QString>
      #include "freeFunctions.h"
      #include "Person.h"

      int main( )
      {
         // Person array for saving
         Person david( "David", "White");
         Person ivan( "Ivan", "Green" );
         std::vector<Person> persons;
         persons.push_back( david );
         persons.push_back( ivan );

      try {
             // Parse the person array to the string content
             QString content;
             parsePersonsToStrContent( persons, content );

      // Save the string content to the file
             QString fileName = "file.txt";
             writeData( fileName, content );

      // Read the string content from the file
             QString readContent;
             readData( fileName, readContent );

      // Parse the string content to the person array
             std::vector<Person> readPersons;
             parseContentToPersons( readContent, readPersons );

      // Print the person array on the screen
             printData( readPersons );
         } catch ( const LogicError &e ) {
             std::cerr << e.what( ) << std::endl;
             return 1;
         } catch ( const FileError &e ) {
             std::cerr << e.what( ) << std::endl;
             return 1;
         } catch ( ... ) {
             std::cerr << "Error: unknown exception" << std::endl;
             return 1;
         }

      return 0;
      }
      [/code]

      Person.h
      [code]
      #ifndef PERSON_H
      #define PERSON_H

      #include <QString>

      class Person {
      public:

      Person( const QString &firstName = "",
                 const QString &lastName = "" ) :
             m_firstName( firstName ),
             m_lastName( lastName )
         {

      }

      QString firstName( ) const
         {
             return m_firstName;
         }

      QString lastName( ) const
         {
             return m_lastName;
         }

      void setFirstName( const QString &firstName )
         {
             m_firstName = firstName;
         }

      void setLastName( const QString &lastName )
         {
             m_lastName = lastName;
         }

      private:
         QString m_firstName;
         QString m_lastName;
      };

      #endif // PERSON_H
      [/code]

      freeFunctions.h
      [code]
      #ifndef FREEFUNCTIONS_H
      #define FREEFUNCTIONS_H

      #include <vector>

      #include <QString>

      #include "FileOpenError.h"
      #include "FileReadError.h"
      #include "FileWriteError.h"
      #include "EmptyArgument.h"
      #include "Person.h"

      void readData( const QString &fileName, QString &content )
      throw ( EmptyArgument, FileOpenError, FileReadError );

      void parseContentToPersons( const QString &content,
                                 std::vector<Person> &persons )
      throw ( EmptyArgument );

      void parsePersonsToStrContent( const std::vector<Person> &persons,
                                    QString &content)
      throw ( EmptyArgument );

      void writeData( const QString &fileName,
                     const QString &content )
      throw ( EmptyArgument, FileOpenError, FileWriteError );

      void printData( const std::vector<Person> &persons )
      throw ( EmptyArgument );

      #endif // FREEFUNCTIONS_H
      [/code]

      1 Reply Last reply
      0
      • 8Observer88 Offline
        8Observer88 Offline
        8Observer8
        wrote on last edited by
        #3

        freeFunctions.cpp
        [code]
        #include <iostream>
        #include <string>
        #include <QFile>
        #include <QRegExp>
        #include <QTextStream>
        #include <QDebug>
        #include "freeFunctions.h"

        void readData(const QString &fileName, QString &content )
        throw ( EmptyArgument, FileOpenError, FileReadError )
        {
           std::string functionName = "readData()";

        // Check argument
           if ( fileName.isEmpty( ) ) {
               throw EmptyArgument( functionName );
           }

        // Open the input file for reading
           QFile file( fileName );
           if( !file.open( QIODevice::ReadOnly ) ) {
               throw FileOpenError( fileName.toStdString( ), functionName );
           }

        // Read the content from the file
           QByteArray data = file.readAll( );
           if ( data.isEmpty( ) ) {
               throw FileReadError( fileName.toStdString( ), functionName );
           }

        content = QString( data );
        }

        void parseContentToPersons( const QString &content, std::vector<Person> &persons )
        throw ( EmptyArgument )
        {
           std::string functionName = "parseContentToPersons()";

        // Check the input argument
           if ( content.isEmpty( ) ) {
               throw EmptyArgument( functionName );
           }

        QRegExp regExp("(\w+) (\w+)");
           int pos = 0;
           while ( ( pos = regExp.indexIn( content, pos ) ) != -1 ) {
               QString firstName = regExp.cap( 1 );
               QString lastName = regExp.cap( 2 );
               Person person( firstName, lastName );
               persons.push_back( person );
               pos += regExp.matchedLength( );
           }
        }

        void parsePersonsToStrContent( const std::vector<Person> &persons,
                                      QString &content)
        throw ( EmptyArgument )
        {
           std::string functionName = "parsePersonsToStrContent()";

        // Check the input argument
           if ( persons.empty( ) ) {
               throw EmptyArgument( functionName );
           }

        for ( std::size_t i = 0; i < persons.size( ); ++i ) {
               QString firstName = persons[i].firstName( );
               QString lastName = persons[i].lastName( );
               QString line = QString( "%1 %2\n" ).arg( firstName ).arg( lastName );
               content.append( line );
           }
        }

        void writeData( const QString &fileName, const QString &content )
        throw ( EmptyArgument, FileOpenError, FileWriteError )
        {
           std::string functionName = "writeData()";

        // Check arguments
           if ( fileName.isEmpty( ) || content.isEmpty( ) ) {
               throw EmptyArgument( functionName );
           }

        // Open the output file for writing
           QFile file( fileName );
           if ( !( file.open( QIODevice::WriteOnly ) ) ) {
               throw FileOpenError( fileName.toStdString( ), functionName );
           }

        // Write data to the output file
           QTextStream stream( &file );
           stream << content;
           if ( stream.status() != QTextStream::Ok ) {
               throw FileWriteError( fileName.toStdString( ), functionName );
           }
        }

        void printData( const std::vector<Person> &persons )
        throw ( EmptyArgument )
        {
           std::string functionName = "printData()";

        // Check the input argument
           if ( persons.empty( ) ) {
               throw EmptyArgument( functionName );
           }

        // Print data
           for ( std::size_t i = 0; i < persons.size( ); ++i ) {
               std::cout << "First Name: " << persons[i].firstName( ).toStdString( ) << std::endl;
               std::cout << "Last Name: " << persons[i].lastName( ).toStdString( ) << std::endl;
               std::cout << std::endl;
           }
        }
        [/code]

        FileError.h
        [code]
        #ifndef FILEERROR_H
        #define FILEERROR_H

        #include <string>
        #include <stdexcept>

        class FileError : public std::runtime_error
        {
        public:

        FileError( const std::string &fileName,
                      const std::string &functionName) :
               std::runtime_error( "" ),
               m_message( "" ),
               m_fileName( fileName ),
               m_functionName( functionName )
           {

        }

        virtual ~FileError( ) throw( )
           {

        }

        virtual const char *what() const throw( )
           {
               return m_message.c_str( );
           }

        std::string message( ) const
           {
               return m_message;
           }

        protected:
           std::string m_message;
           std::string m_fileName;
           std::string m_functionName;
        };

        #endif // FILEERROR_H
        [/code]

        1 Reply Last reply
        0
        • 8Observer88 Offline
          8Observer88 Offline
          8Observer8
          wrote on last edited by
          #4

          FileOpenError.h
          [code]
          #ifndef FILEOPENERROR_H
          #define FILEOPENERROR_H

          #include <string>
          #include "FileError.h"

          class FileOpenError : public FileError {
          public:

          FileOpenError( const std::string &fileName,
                            const std::string &functionName) :
                 FileError( fileName, functionName )
             {
                 m_message = "Error: unable to open the file "" +
                         m_fileName + "" in the function "" +
                         m_functionName + """;
             }
          };

          #endif // FILEOPENERROR_H
          [/code]

          FileReadError.h
          [code]
          #ifndef FILEREADERROR_H
          #define FILEREADERROR_H

          #include <string>
          #include "FileError.h"

          class FileReadError : public FileError {
          public:

          FileReadError( const std::string &fileName,
                            const std::string &functionName ) :
                 FileError( fileName, functionName )
             {
                 m_message = "Error: unable to read the file "" + m_fileName +
                         "" in the function "" + m_functionName + """;
             }
          };

          #endif // FILEREADERROR_H
          [/code]

          FileWriteError.h
          [code]
          #ifndef FILEWRITEERROR_H
          #define FILEWRITEERROR_H

          #include <string>
          #include "FileError.h"

          class FileWriteError : public FileError {
          public:

          FileWriteError( const std::string &fileName,
                             const std::string &functionName ) :
                 FileError( fileName, functionName )
             {
                 m_message = "Error: unable to write to the file " +
                         m_fileName + " in the function " + m_functionName;
             }
          };

          #endif // FILEWRITEERROR_H
          [/code]

          EmptyArgument.h
          [code]
          #ifndef EMPTYARGUMENT_H
          #define EMPTYARGUMENT_H

          #include <string>
          #include "LogicError.h"

          class EmptyArgument : public LogicError {
          public:

          EmptyArgument( const std::string &functionName ) :
                 LogicError( functionName )
             {
                 m_message = "Error: empty argument in the "
                         "function " + m_functionName;
             }
          };

          #endif // EMPTYARGUMENT_H
          [/code]

          LogicError.h
          [code]
          #ifndef LOGICERROR_H
          #define LOGICERROR_H

          #include <string>
          #include <stdexcept>

          class LogicError : public std::logic_error
          {
          public:

          LogicError( const std::string &functionName ) :
                 std::logic_error( "" ),
                 m_functionName( functionName ),
                 m_message( "" )
             {

          }

          virtual ~LogicError( ) throw( )
             {

          }

          virtual const char *what( ) const throw( )
             {
                 return m_message.c_str( );
             }

          std::string message( ) const
             {
                 return m_message;
             }

          protected:
             std::string m_functionName;
             std::string m_message;
          };

          #endif // LOGICERROR_H
          [/code]

          1 Reply Last reply
          0
          • G Offline
            G Offline
            giesbert
            wrote on last edited by
            #5

            Hi,

            there is no this is how to handle errors in C++. From my POV, there are two ways to do it:

            Exception handling

            return values

            I prefer return values as exceptions for me are for exceptional cases (no more memory...) and not for 'normal' errors.

            Qt also does not use exception handling, so if you are inside Qt calls, make sure never to throw exceptions back to the event loop.

            Nokia Certified Qt Specialist.
            Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

            1 Reply Last reply
            0
            • 8Observer88 Offline
              8Observer88 Offline
              8Observer8
              wrote on last edited by
              #6

              Gerolf, thank you! What do you think about my class Receiver? Can I use it in large projects?

              [CODE]
              void MainWindow::runReceiver()
              {
              try {
              m_receiver->run();
              connect( m_receiver, SIGNAL( signalReceivedData( QByteArray ) ),
              this, SLOT( slotReceivedData( QByteArray ) ) );
              } catch ( const PortError &e ) {
              QString message( e.what() );
              QMessageBox::information( this, tr( "Error" ), message );
              return;
              } catch( ... ) {
              QString message( "Error: unknown exception" );
              QMessageBox::information( this, tr( "Error" ), message );
              return;
              }
              }
              [/CODE]

              Receiver.h
              [CODE]
              #ifndef RECEIVER_H
              #define RECEIVER_H

              #include <QObject>
              #include <QString>
              #include <QSerialPort>
              #include <stdexcept>
              #include <string>
              #include "PortError.h"

              class Receiver : public QObject {
              Q_OBJECT
              public:

              Receiver( const QString &portName = QString( "COM2" ),
                        QSerialPort::BaudRate baudRate = QSerialPort::Baud9600,
                        QSerialPort::DataBits dataBits = QSerialPort::Data8,
                        QSerialPort::Parity parity = QSerialPort::NoParity,
                        QSerialPort::StopBits stopBits = QSerialPort::OneStop,
                        QSerialPort::FlowControl flowControl = QSerialPort::NoFlowControl );
              
              Receiver( const Receiver &receiver );
              
              ~Receiver();
              
              void run( ) throw( PortError );
              
              QString getPortName() const;
              QSerialPort::BaudRate getBaudRate() const;
              QSerialPort::DataBits getDataBist() const;
              QSerialPort::Parity getParity() const;
              QSerialPort::StopBits getStopBits() const;
              QSerialPort::FlowControl getFlowControl() const;
              

              signals:
              void signalReceivedData( QByteArray data );

              private slots:
              void slotReadyRead( );

              private:
              QSerialPort m_serialPort;
              QString m_portName;
              QSerialPort::BaudRate m_baudRate;
              QSerialPort::DataBits m_dataBits;
              QSerialPort::Parity m_parity;
              QSerialPort::StopBits m_stopBits;
              QSerialPort::FlowControl m_flowControl;
              };

              #endif // RECEIVER_H
              [/CODE]

              Receiver.cpp
              [CODE]
              #include "Receiver.h"

              Receiver::Receiver( const QString &portName,
              QSerialPort::BaudRate baudRate,
              QSerialPort::DataBits dataBits,
              QSerialPort::Parity parity,
              QSerialPort::StopBits stopBits,
              QSerialPort::FlowControl flowControl ) :
              m_portName( portName ),
              m_baudRate( baudRate ),
              m_dataBits( dataBits ),
              m_parity( parity ),
              m_stopBits( stopBits ),
              m_flowControl( flowControl )
              {
              }

              Receiver::Receiver( const Receiver &receiver )
              {
              this->m_portName = receiver.getPortName();
              this->m_baudRate = receiver.getBaudRate();
              this->m_dataBits = receiver.getDataBist();
              this->m_parity = receiver.getParity();
              this->m_stopBits = receiver.getStopBits();
              this->m_flowControl = receiver.getFlowControl();
              }

              Receiver::~Receiver()
              {
              m_serialPort.close();
              }

              void Receiver::run( ) throw( PortError )
              {
              m_serialPort.setPortName( m_portName );

              if ( !m_serialPort.open( QIODevice::ReadOnly ) ) {
                  throw PortError( m_portName.toStdString() );
              }
              
              m_serialPort.setBaudRate( m_baudRate );
              m_serialPort.setDataBits( m_dataBits );
              m_serialPort.setParity( m_parity );
              m_serialPort.setStopBits( m_stopBits );
              m_serialPort.setFlowControl( m_flowControl );
              
              connect( &m_serialPort, SIGNAL( readyRead( ) ),
                       this, SLOT( slotReadyRead( ) ) );
              

              }

              QString Receiver::getPortName() const
              {
              return m_portName;
              }

              QSerialPort::BaudRate Receiver::getBaudRate() const
              {
              return m_baudRate;
              }

              QSerialPort::DataBits Receiver::getDataBist() const
              {
              return m_dataBits;
              }

              QSerialPort::Parity Receiver::getParity() const
              {
              return m_parity;
              }

              QSerialPort::StopBits Receiver::getStopBits() const
              {
              return m_stopBits;
              }

              QSerialPort::FlowControl Receiver::getFlowControl() const
              {
              return m_flowControl;
              }

              void Receiver::slotReadyRead( )
              {
              QByteArray data;
              data = m_serialPort.readAll( );
              emit signalReceivedData( data );
              }
              [/CODE]

              PortError.h
              [CODE]
              #ifndef PORTERROR_H
              #define PORTERROR_H

              #include <stdexcept>
              #include <string>

              class PortError : public std::runtime_error
              {
              public:
              PortError( const std::string &portName ) : std::runtime_error( "" )
              {
              m_message = "Error: unable to open the port "" +
              portName + """;
              }

              virtual ~PortError() throw()
              {
              
              }
              
              virtual const char *what() const throw()
              {
                  return m_message.c_str();
              }
              
              std::string getMessage()
              {
                  return m_message;
              }
              

              private:
              std::string m_message;
              };

              #endif // PORTERROR_H
              [/CODE]

              1 Reply Last reply
              0
              • A Offline
                A Offline
                Asperamanca
                wrote on last edited by
                #7

                [quote author="Gerolf" date="1413793241"]Hi,

                there is no this is how to handle errors in C++. From my POV, there are two ways to do it:

                Exception handling

                return values

                [/quote]

                I would throw a third way into the mix - although it is closely related to return values, and applicable only in certain cases: Error status as a class member.
                Suppose we have a class that opens a file, reads its content, does something and closes the file again. We could structure it like this

                @class FileProcessor
                {
                public:
                void handleFile(const QString& fileName);
                ErrorStatus getErrorStatus() const;
                SomeDataClass getProcessedData() const;

                private:
                void openFile();
                void readFile();
                void processData();
                void closeFile();

                ErrorStatus m_ErrorStatus;

                QString m_CurrentFileName;

                // Some temporary member variables...not important for this discusssion
                }@

                The methods would be implemented in such a way:

                @void FileProcessor::handleFile(const QString& fileName)
                {
                m_CurrentFileName = fileName;

                openFile();
                readFile();
                processData();
                closeFile();
                }

                void FileProcessor::openFile()
                {
                if (m_ErrorStatus.isErrorSet())
                {
                return;
                }

                if ( ! QFile::exists(m_CurrentFileName) )
                {
                // Ooops...file does not exist
                m_ErrorStatus.setError("File does not exist");
                return;
                }
                // Open the file - set errors if they happen, as above
                }

                void FileProcessor::readFile()
                {
                if (m_ErrorStatus.isErrorSet())
                {
                return;
                }
                // Read the file - set errors if they happen
                }

                void FileProcessor::processData()
                {
                if (m_ErrorStatus.isErrorSet())
                {
                return;
                }
                // Process the data - set errors if they happen
                }

                void FileProcessor::closeFile()
                {
                if (m_ErrorStatus.isErrorSet())
                {
                return;
                }
                // Close the file - set errors if they happen
                }

                ErrorStatus FileProcessor::getErrorStatus() const
                {
                return m_ErrorStatus;
                }@

                The caller would use this class in this way:

                @
                FileProcessor processor;
                processor.handleFile(myFilename);
                if (processor.getErrorStatus().isErrorSet())
                {
                // Log, report, whatever
                }
                else
                {
                // Use data and continue
                }
                @

                Edit: Insert nod to "Clean Code" by Robert C. Martin

                1 Reply Last reply
                0
                • JKSHJ Offline
                  JKSHJ Offline
                  JKSH
                  Moderators
                  wrote on last edited by
                  #8

                  [quote author="Asperamanca" date="1414597531"]I would throw a third way into the mix - although it is closely related to return values, and applicable only in certain cases: Error status as a class member.[/quote]That's a good one.

                  An example of a Qt class that does this is "http://qt-project.org/doc/qt-5/qxmlstreamreader.html":QXmlStreamReader. See the following functions:

                  • QXmlStreamReader::raiseError()
                  • QXmlStreamReader::hasError()
                  • QXmlStreamReader::error()
                  • QXmlStreamReader::errorString()

                  Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                  1 Reply Last reply
                  0
                  • 3 Offline
                    3 Offline
                    3dh3dh.de
                    wrote on last edited by
                    #9

                    ...but ErrorStatus means: Having a by design not multithreading / reentrant class.

                    To not break parallel calls and to be more safe it's better to treat each method delivering an error status separately. So return values (classes, enums etc.) are better and for critical program flow or memory errors exceptions are part of the ANSI C++ standard (see: new/delete).

                    But: As mentioned before Qt doesn't handle exceptions everywhere - so throwing inside a slot or event handling method can crash your app. No: Not can - it will ;)

                    ciao,
                    Chris

                    // http://3DH.de

                    1 Reply Last reply
                    0
                    • 3 Offline
                      3 Offline
                      3dh3dh.de
                      wrote on last edited by
                      #10

                      ...but ErrorStatus means: Having a by design not multithreading / reentrant class.

                      To not break parallel calls and to be more safe it's better to treat each method delivering an error status separately. So return values (classes, enums etc.) are better and for critical program flow or memory errors exceptions are part of the ANSI C++ standard (see: new/delete).

                      But: As mentioned before Qt doesn't handle exceptions everywhere - so throwing inside a slot or event handling method can crash your app. No: Not can - it will ;)

                      ciao,
                      Chris

                      // http://3DH.de

                      1 Reply Last reply
                      0
                      • 8Observer88 8Observer8

                        Hi

                        Please talk me about your strategy of handling errors

                        What do you think about this?

                        main.cpp
                        [CODE]
                        #include <iostream>
                        #include "Calculator.h"

                        int main()
                        {
                        Calculator<float> calculator;

                        try {
                            float result = calculator.divide( 24.7f, 3.0f );
                            std::cout << "Result = " << result << std::endl;
                        } catch ( const LogicError &e ) {
                            std::cerr << e.what() << std::endl;
                            return 1;
                        } catch ( ... ) {
                            std::cerr << "Error: unknown expection" << std::endl;
                            return 1;
                        }
                        
                        return 0;
                        

                        }[/CODE]

                        Calculator.h
                        [CODE]
                        #ifndef CALCULATOR_H
                        #define CALCULATOR_H

                        #include <string>
                        #include "DivideByZero.h"
                        #include "OutOfRange.h"

                        template <typename Type>
                        class Calculator
                        {
                        public:
                        // Divide nums from the range [-1000, 1000]
                        Type divide( Type a, Type b )
                        throw ( DivideByZero, OutOfRange<int> )
                        {
                        std::string functionName = "Calculator::divide()";
                        if ( b == 0 ) {
                        throw DivideByZero( functionName );
                        }

                            const int beginOfRange = -1000;
                            const int endOfRange = 1000;
                        
                            if ( ( a < beginOfRange ) || ( a > endOfRange ) ||
                                 ( b < beginOfRange ) || ( b > endOfRange ) )
                            {
                                throw OutOfRange<int>( beginOfRange,
                                                       endOfRange,
                                                       functionName );
                            }
                        
                            return a / b;
                        }
                        

                        };

                        #endif // CALCULATOR_H[/CODE]

                        DivideByZero.h
                        [CODE]
                        #ifndef DIVIDEBYZERO_H
                        #define DIVIDEBYZERO_H

                        #include <string>
                        #include "LogicError.h"

                        class DivideByZero : public LogicError
                        {
                        public:
                        DivideByZero( const std::string &functionName ) :
                        LogicError( functionName )
                        {
                        m_message = "Error: divide by zero in the "
                        "function " + m_functionName;
                        }
                        };

                        #endif // DIVIDEBYZERO_H[/CODE]

                        OutOfRange.h
                        [CODE]
                        #ifndef OUTOFRANGE_H
                        #define OUTOFRANGE_H

                        #include <string>
                        #include "LogicError.h"

                        template <typename Type>
                        class OutOfRange : public LogicError
                        {
                        public:
                        OutOfRange( Type beginOfRange,
                        Type endOfRange,
                        const std::string &functionName ) :
                        LogicError( functionName )
                        {
                        m_message = "Error: values must be from the range "
                        "[" + std::to_string( beginOfRange ) +
                        ", " + std::to_string( endOfRange ) + "]"
                        " in the function " + m_functionName;
                        }
                        };

                        #endif // OUTOFRANGE_H[/CODE]

                        LogicError.h
                        [CODE]
                        #ifndef LOGICERROR_H
                        #define LOGICERROR_H

                        #include <string>
                        #include <stdexcept>

                        class LogicError : public std::logic_error
                        {
                        public:

                        LogicError( const std::string &functionName ) :
                            std::logic_error( "" ),
                            m_functionName( functionName ),
                            m_message( "" )
                        {
                        
                        }
                        
                        virtual ~LogicError( ) throw( )
                        {
                        
                        }
                        
                        virtual const char *what( ) const throw( )
                        {
                            return m_message.c_str( );
                        }
                        
                        std::string message( ) const
                        {
                            return m_message;
                        }
                        

                        protected:
                        std::string m_functionName;
                        std::string m_message;
                        };

                        #endif // LOGICERROR_H[/CODE]

                        ? Offline
                        ? Offline
                        A Former User
                        wrote on last edited by
                        #11

                        @8Observer8 On his page, Jon K. talks about C++ exceptions.

                        http://exceptionsafecode.com/

                        There's a useful class (esc.hpp) there at the bottom (under the video's). Jon K.'s main points are:
                        Exception-Safety Guidelines

                        • Throw by value. Catch by reference.
                        • No dynamic exception specifications. Use noexcept.
                        • Destructors that throw are evil.
                        • Use RAII. [esc.hpp] (Every responsibility is an object. One responsibility per object.)
                        • All cleanup code called from a destructor.
                        • Support swapperator (With No-Throw Guarantee)
                        • Draw "Critical Lines" for the Strong Guarantee
                        • Know where to catch (Switch/Strategy/Some Success)
                        • Prefer exceptions to error codes
                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved