Home > OS >  Program terminates even after exception handling
Program terminates even after exception handling

Time:06-12

I have a try catch block, as far as I know if an exception is throw I handle it in catch block and then program continues to work which is not happening in my case.

main.cpp inside main function

    const Matrix<int, 3, 2> m1; // Creates 3*2 matrix, with all the default elements set to 0;
    Matrix<int, 3, 3> m2(4); // Creates 3*3 matrix, with the default elements equals to 4;
    const Matrix<int, 3, 3> m3 = m2; // C-py constructor may take O(MN) and not O(1).
    try
    {
        cout << m2   m3 << endl;
        cout << m3 * m1 << endl; // You can choose the format of matrix printing;
        cout << m1 * m2;         // This should throw an exception
    }
    catch (const Matrix<int, 3, 2>::IllegalOperation &e)
    {
        cout << e.what() << endl;
    }
    cout << m2[0][0] << " " << m2[1][0] << endl; // Should print "13 4"

Header file from where everything is imported from

template <class T, int M, int N>
class Matrix
{
private:
    T mat[M][N];
    int rows = M;
    int cols = N;

Edit as per johns solution Error class definition.

// Error class
    class IllegalOperation : public std::exception
    {
    public:
        IllegalOperation(const char *msg) _msg(msg){};
        virtual const char *what() const throw() { return _msg.c_str(); };

    private:
        std::string _msg;
    };

I am getting errors here.

In file included from main.cpp:3:
matrix.h:16:41: error: expected ‘;’ at end of member declaration
   16 |         IllegalOperation(const char *msg) _msg(msg){};
      |                                         ^
      |                                          ;
matrix.h:16:48: error: ‘msg’ has not been declared
   16 |         IllegalOperation(const char *msg) _msg(msg){};
      |                                                ^~~
matrix.h:16:43: error: ISO C   forbids declaration of ‘_msg’ with no type [-fpermissive]
   16 |         IllegalOperation(const char *msg) _msg(msg){};
      |                                           ^~~~
matrix.h:20:21: error: ‘std::string Matrix<T, M, N>::IllegalOperation::_msg’ conflicts with a previous declaration
   20 |         std::string _msg;
      |                     ^~~~
matrix.h:16:43: note: previous declaration ‘int Matrix<T, M, N>::IllegalOperation::_msg(int)’
   16 |         IllegalOperation(const char *msg) _msg(msg){};
      |                                           ^~~~
matrix.h: In member function ‘int Matrix<T, M, N>::IllegalOperation::_msg(int)’:
matrix.h:16:53: warning: no return statement in function returning non-void [-Wreturn-type]
   16 |         IllegalOperation(const char *msg) _msg(msg){};
      |                                                     ^
matrix.h: In member function ‘virtual const char* Matrix<T, M, N>::IllegalOperation::what() const’:
matrix.h:17:59: error: invalid use of member function ‘int Matrix<T, M, N>::IllegalOperation::_msg(int)’ (did you forget the ‘()’ ?)
   17 |         virtual const char *what() const throw() { return _msg.c_str(); };
      |                                                           ^~~~
matrix.h:17:64: error: expected ‘;’ before ‘c_str’
   17 |         virtual const char *what() const throw() { return _msg.c_str(); };
      |                                                                ^~~~~
matrix.h:17:64: error: there are no arguments to ‘c_str’ that depend on a template parameter, so a declaration of ‘c_str’ must be available [-fpermissive]
matrix.h:17:64: note: (if you use ‘-fpermissive’, G   will accept your code, but allowing the use of an undeclared name is deprecated)
matrix.h: In instantiation of ‘const char* Matrix<T, M, N>::IllegalOperation::what() const [with T = int; int M = 3; int N = 2]’:
main.cpp:35:23:   required from here
matrix.h:17:69: error: ‘c_str’ was not declared in this scope; did you mean ‘wcsstr’?
   17 |         virtual const char *what() const throw() { return _msg.c_str(); };
      |                                                                ~~~~~^~
      |                                                                wcsstr
matrix.h: In instantiation of ‘const char* Matrix<T, M, N>::IllegalOperation::what() const [with T = int; int M = 3; int N = 3]’:
matrix.h:17:29:   required from here
matrix.h:17:69: error: ‘c_str’ was not declared in this scope; did you mean ‘wcsstr’?
   17 |         virtual const char *what() const throw() { return _msg.c_str(); };
      |                                                                ~~~~~^~
      |                                                                wcsstr

Continuation of the header file

    // constructor
    Matrix(int v = 0)
    {
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                mat[i][j] = v;
        }
    }

    // () overloading
    T &operator()(int i, int j)
    {
        return mat[i][j];
    };

    const T &operator()(int i, int j) const
    {
        return mat[i][j];
    };

    // [] overloading
    T *operator[](int index)
    {
        return mat[index];
    };
    const T *operator[](int index) const
    {
        return mat[index];
    };

    // << overloading
    friend std::ostream &operator<<(std::ostream &os, const Matrix<T, M, N> &L)
    {
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                os << L.mat[i][j] << " ";
            os << "\n";
        }
        return os;
    };

    template <class T1, int M1, int N1>
    Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other);
    template <class T1, int M1, int N1>
    const Matrix<T, M, N1> operator*(Matrix<T1, M1, N1> const &other) const;
    Matrix<T, M, N> operator (Matrix<T, M, N> const &other);

    friend T min(Matrix obj)
    {
        T result = obj.mat[0][0];
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                if (result < obj.mat[i][j])
                    result = obj.mat[i][j];
        }
        return result;
    };

    long double avg() const
    {
        long double result = 0;
        for (int i = 0; i < M; i  )
        {
            for (int j = 0; j < N; j  )
                if (result < mat[i][j])
                    result = result   mat[i][j];
        }
        return result / (M * N);
    }
};

template <class T, int M, int N>
Matrix<T, M, N> Matrix<T, M, N>::operator (Matrix const &other)
{
    if ((this->rows == other.rows) && (this->cols == other.cols))
    {
        Matrix<T, M, N> resultantMatrix;

        for (auto i = 0; i < this->rows; i  )
        {
            for (auto j = 0; j < this->cols; j  )
            {
                auto &valueFirst = this->mat[i][j];
                auto &valueSecond = other.mat[i][j];

                // if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                //     throw std::out_of_range("Resultant value of matrix is out of range");
                // else
                resultantMatrix(i, j) = valueFirst   valueSecond;
            }
        }
        return resultantMatrix;
    }
    else
        throw("Matrices cannot be added, sizes do not match");
}

template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, N1> Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other)
{
    std::cout << M << " " << N1;
    if (N == M1)
    {
        Matrix<T, M, N1> resultantMatrix;

        for (auto i = 0; i < this->rows; i  )
        {
            for (auto j = 0; j < this->cols; j  )
            {
                for (auto k = 0; k < this->cols; k  )
                {
                    auto &valueFirst = this->mat[i][k];
                    auto &valueSecond = other(k, j);

                    // if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                    //     throw std::out_of_range("Resultant value of matrix is out of range");
                    // else
                    resultantMatrix(i, j)  = valueFirst * valueSecond;
                }
            }
        }
        return resultantMatrix;
    }
    else
        throw("Matrices cannot be added, sizes do not match");
}

template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, N1> const Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other) const
{
    if (N == M1)
    {
        Matrix<T, M, N1> resultantMatrix;

        for (auto i = 0; i < this->rows; i  )
        {
            for (auto j = 0; j < this->cols; j  )
            {
                for (auto k = 0; k < this->cols; k  )
                {
                    auto &valueFirst = this->mat[i][k];
                    auto &valueSecond = other(k, j);

                    // if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                    //     throw std::out_of_range("Resultant value of matrix is out of range");
                    // else
                    resultantMatrix(i, j)  = valueFirst * valueSecond;
                }
            }
        }
        return resultantMatrix;
    }
    else
        throw("Matrices cannot be added, sizes do not match");
}

Output at the end

terminate called after throwing an instance of 'char const*'
Aborted (core dumped)

Why is the core getting dumped? I have thrown an error, I have handled it. What am I missing? Any help is appreciated! Thank you.

CodePudding user response:

First move the exception class outside of the matrix class

template <class T, int M, int N>
class Matrix
{
};

class IllegalOperation
{
};

The way you have it now, every different kind of matrix class throws a different kind of exception. That's going to make using the exception class really difficult..

Make the same change to your catch block (and make it catch a const reference)

catch (const IllegalOperation &e)

Add constructor etc. to your exception class, (exception classes are no different from any other class, they need constructors and methods and members). Although not completely necessary, it's reasonable to derive the exception class from std::exception as I've done below. If you haven't done this already you'll need to add the header for std::exception

#include <exception>

...

class IllegalOperation : public std::exception
{
public:
    IllegalOperation(const char* msg) : _msg(msg) {}
    virtual const char *what() const { return _msg.c_str(); }
private:
    std::string _msg;
};

Finally throw your exception class, not a string.

throw IllegalOperation("Matrices cannot be added, sizes do not match");

CodePudding user response:

You have two key problems overall. First, you should move the exception type (ie. class) out of the Matrix's definition and make it an independent type. This is because the exception is logically from the matrix and just a means to correctly handle errors, thus not required to construct a valid matrix.

class IllegalOperation 
{ /* Definition goes here */};

template<typename T, int M, int N>
class Matrix
{ /* Definition goes here */ };

The second problem is that when you are throwing the exceptions, you are throwing a them with a const char*, ie. a string literal, which is not what you catch expression is expecting, thus because the an exception is thrown but not caught, the program terminates. In order to throw the exception that you are expecting you need to;

  1. (i) construct a more rigorous exception type that has a constructor that takes a string literal or a std::string (or an other string type); (ii) or inherit from one of the standard libraries exceptions, giving you access to these constructors as they are already defined. @Brett Hale suggested std::logic_error which is a great place to start. As it carries the semantic value that the error is a logical error. std::invalid_argument is also a good choice that is a little more specific (and derived from std::logic_error itself). Exceptions are found in the stdexcept header. If you do derive from a standard exception, you will still need to create a constructor but you can just call the parent types constructor within your constructor.
#include <stdexcept>

/* ... */

class IllegelOperation : public std::logic_error 
{
    IllegelOperation(const std::string& s_error)
    : std::logic_error(s_error.c_str())
    { }

    /// Note: no need for IllegelOperation::what() as std::logic_error handles that
};
  1. Second, where the exceptions are being thrown, you need to throw the actual exception you want. An example throw expression would be:
throw IllegelOperation("message");

This means that your catch expression should look like:

catch (const IllegelOperation& e)
{ /* handle error */ }

Hopefully this helps.

  •  Tags:  
  • c
  • Related