-2

I have a matrixType File that works fine, but I am now trying to replace the if statements with the try, catch, and throw statements within a function of a class. I am just trying to understand one function so I can apply it to the others. Since I did try to do the try and catch statements but it skipped over the try statement and caused an actual exception that stops the program completely. The One function I am focusing on is the equal operator Here is the HeaderFile #pragma once #include #include #include #include #include #include

using namespace std;

class matrixType
{
private:
    int **matrix;
    int row;
    int col;
public:
    const matrixType& operator=(const matrixType& mat);
}

Here is the class.cpp file that currently works

#include "matrixType.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include <stdexcept>
#include <limits>

using namespace std;

const matrixType& matrixType::operator=(const matrixType& mat)
{
    if (row != mat.row || col != mat.col)
    {
        cout << "The matrixes are not identical" << endl;
        return *this;
    }
    for (int i = 0; i < row; i++)
    {
        for (int r = 0; r < col; r++)
        {
            matrix[i][r] = mat.matrix[i][r];
        }
    }
    return *this;
}

Then this is the source file

#include <iostream>
#include <string>
#include <stdexcept>
#include <limits>
#include "matrixType.h"
using namespace std;

int main()
{
    matrixType test1(3, 3);
    matrixType test2(2, 2);
    test1 = test2;

    return 0;
}

So the big question is how do you throw an exception I tried

Try
{
   if(mat.row != row || mat.col != col)
        throw exception("The matrixes are not identical")
}
catch (exception & e)
{
   cout << e.what << endl;
}

Which caused the actual exception to pop up but when I leave the if statement it works and does not go into a fail state. Does anyone see what I was doing wrong if I replaced the if statement with the code above?

Derek Langer
  • 29
  • 1
  • 7
  • 1
    You use exceptions to bubble an error up the call-stack to the first caller who knows how to handle it. If you directly catch it after throwing, how can it bubble up? – Deduplicator Feb 28 '19 at 00:52
  • What does bubbling it up mean? – Derek Langer Feb 28 '19 at 00:54
  • Move up the hierarchy, in this case stack. – Deduplicator Feb 28 '19 at 00:55
  • Create a [mcve] – eerorika Feb 28 '19 at 00:57
  • What do you mean by "go into a fail state"? What is a "fail state"? What does "going into it" mean? – eerorika Feb 28 '19 at 00:58
  • The `operator=` should do what is expected, and that is to make a copy of the passed-in `matrixType` -- it shouldn't matter if the passed-in matrix is a different size. When a programmer does this `matrixType a(1,1); matrixType b(2,2); b = a;`, they expect `b` to be a 1x1 matrix equal to `a`. Did you get this code from a teacher or a book? If a teacher, get a new teacher, if a book, get a different book. – PaulMcKenzie Feb 28 '19 at 01:21

2 Answers2

1

First, a note about the meaning of exceptions. Further down, I'll address what's wrong with your code.

The meaning of throwing an exception in C++, in English, is roughly, "I can't deal with this situation anymore, I'm giving up right now, and I'm hoping that somebody else can deal with this." The meaning of catching an exception is roughly, "oops, somebody screwed up, but I'm going to do something about it now." With this in mind, let's look at how this works in more concrete detail.

Many functions have preconditions, which are things that function always expects to be true before it runs. For example, a squareRoot(double x) function might have a precondition that x must never be negative. When a function's precondition is violated, it's a natural time for that function to say "I'm giving up right now, deal with it!" since somebody who called that function is doing something wrong, and squareRoot can't possibly fix that. This could look like the following:

// precondition: x must not be negative
double squareRoot(double x){
    if (x < 0.0){
        // precondition is violated
        throw std::runtime_error("input to squareRoot was negative");
        // the function exits here!
        // this point in code is not reachable
    }
    // otherwise, precondition is satisfied, it's safe to continue
    ...
    return result;
}

elsewhere, in the wild:

void myFunction(){
    double x;
    cout << "x = ";
    cin >> x;
    double y = squareRoot(x);
    cout << ", y = " << y << '\n';
}

Here, if somebody types in a negative number, then the preconditions of squareRoot are violated, and it throws an exception. This means that squareRoot will not return normally, and neither will myFunction. When exception is thrown, everything is interrupted until you catch the exception, which can happen far outside the current function.

int main(){
    try {
        myFunction(); // this might throw

        // if myFunction() throws, the following output will not happen!
        cout << "Thanks! have a nice day.\n";
    } catch (std::runtime_error e) {
        // if myFunction() does throw, the error lands right here
        cout << "Oops! an error occurred: " << e.what() << '\n';
    }
    return 0;
}

It's important to note that you should only throw exceptions when something is really wrong. Exceptions are not a replacement for ordinary program logic, and they're not a replacement for validating things like user input.


About custom classes:

When you're defining a custom class type, if it has either a copy constructor, copy assignment operator, or destructor, that probably means that your class has sensitive information that needs special care to clean up and keep track of. If you've written at least one of these functions, you should implement all three of them. Otherwise, it's extremely easy to introduce memory leaks, false data sharing, and all kinds of unwanted Undefined Behavior into your program.


About your copy assignment operator:

The purpose of a copy assignment operator, as in a = b; is that after it runs, the left-hand object should be logically identical to the right-hand object, and the right-hand object should not have changed. The previous state of the left-hand object is lost at this point. What exactly logically identical means is a question of what your class is representing.

In the case a simple matrix, I would expect two matrices to be identical when they have the same width, height, and values for all elements, and I would implement a copy assignment operator accordingly. For example:

Matrix& Matrix::operator=(const Matrix& other){
    releaseMemory(); // clean up old data
    resize(other.rows, other.cols); // allocate new data
    for (int i = 0; i < rows; ++i){
        for (int j = 0; j < cols; ++j){
            this->data[i][j] = other.data[i][j]; // copy each value
        }
    }
    return *this;
}

I leave the implementation of the details to you. You should be able to find great examples and detailed explanations of how to overload operators, write your own copy constructor and destructor, and about good practice in general by reading a good C++ book.

alter_igel
  • 6,899
  • 3
  • 21
  • 40
-1

Actually, I figured it out I have to use return statements as it worked when I included a return statement within the catch function.

Derek Langer
  • 29
  • 1
  • 7
  • No. More than likely, your matrix class violates the [rule of 3](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – PaulMcKenzie Feb 28 '19 at 01:27