Handling Exceptions in C ++

2

I have a question regarding the handling of exceptions in C ++, the class Fracao below is purposely incomplete does not even have setters or getters and several things were " left "side, has only two attributes and a constructor, and if the denominator receives zero, an exception will be thrown inside the constructor.

The code works perfectly, what I would like to know is if it is possible to do not only the throwing of the exception inside the constructor / class method, but also the handling of it, ie taking the blocks try and% with catch , and treat it elsewhere avoiding that every time I need to create any object (of type int main in this case) has to create it inside a block Fracao , followed by a try .

#include <iostream>
#include <exception>

using namespace std;

class Fracao
{
private:
    int numerador;
    int denominador;

public:
    Fracao(int numerador, int denominador);
};


Fracao::Fracao(int numerador, int denominador)
{
    this->numerador = numerador;

    if(denominador != 0)
        this->denominador = denominador;
    else
        throw "Impossivel dividir por zero";
}

int main()
{

    try
    {
        Fracao f1(1, 0);
    }
    catch(const char* msg)
    {
        cerr << "Erro: " << msg << endl;
    }
    catch(...)
    {
        cerr << "Erro desconhecido\n";
    }

    return 0;
}
    
asked by anonymous 28.09.2016 / 01:26

2 answers

3

Have some possible solutions, even do not use exception. If the object construct has a contract that raises an exception when creation fails you have to catch the exception and decide what to do.

Note that if this is considered a programming error and nothing should be done you can leave the exception unhandled or treat it generically in one place. And this place would probably be the main() function. That is the case that seems to be being done. I would not do otherwise. In a more complex application that calls other functions there is a big chance that I would not do otherwise. It would only give you a slightly better error message, log in log or something. That is, capture the exception as far as possible from where it occurred. In case you can not go too far everything happens in main() .

If you want to do something specific and try to solve the situation (you should only catch exceptions that can solve the situation) there you have to catch the exception in the place that it can be generated. There it is to capture as close as possible that makes sense.

What you can do to make it easier is to create a function to manipulate the error and call them instead of treating them everywhere. This is only valid if the treatment is always the same.

Of course, maybe the class should do better and do not need it all, but that's just a guess, it depends a lot on the case. You also have reasons not to do that.

If you want to do the function it would look something like this:

#include <iostream>
#include <exception>
using namespace std;

class Fracao {
private:
    int numerador;
    int denominador;
 public:
    Fracao(int numerador, int denominador);
};

Fracao::Fracao(int numerador, int denominador) {
    this->numerador = numerador;
    if(denominador != 0) {
        this->denominador = denominador;
    } else {
        throw "Impossivel dividir por zero";
    }
}

Fracao HandleExceptionFracao(int numerador, int denominador) {
    try {
        Fracao f(numerador, denominador);
        return f;
    } catch (const char* msg) {
        cerr << "Erro: " << msg << endl;
    } catch(...) {
        cerr << "Erro desconhecido\n";
    }
}

int main() {
    Fracao f1 = HandleExceptionFracao(1, 0);
}

See running on ideone .

It even gives you a generic function that serves to create any object and handle the exception in the same way. But I still think that according to the example of the question the error is programming and the treatment should be generalized.

It would be interesting to read about exceptions on the site . Most are not for C ++, but most concepts are universal. Very few programmers know how to use or understand what an exception is and how (not) one should treat it.

    
28.09.2016 / 01:51
0

You can imitate what other programming languages do, such as Java, where there is an interface Trowable , all the execiones launched in Java must implement this interface, so the virtual machine will take care of all exceptions, so in C ++ you would do the following:

Declare your Exception class that will serve as a basis for it to always be captured;

class RunnableException {
private:

public:
    virtual std::string getMessage() =0;
};

Create a specific class to throw the invalid denominator exception;

class ValorInvalidoException : public RunnableException {
private:
    std::string message;

public:
    ValorInvalidoException(std::string message) {
        this->message = message;
    }

    std::string getMessage() { 
        return this->message;
    };
};

Instead of launching a const char *, you must launch an object;

Fracao::Fracao(int numerador, int denominador)
{
    this->numerador = numerador;

    if(denominador != 0)
        this->denominador = denominador;
    else
        throw ValorInvalidoException("Impossivel dividir por zero");
};

Use a single try-catch involving your entire main function;

int main() {
    try {
        //faca seu codigo do main normalmente
        Fracao f1(1, 0);
        try {

        } catch (ExcecaoEspecifica e) {
            //coloquei esse try catch aqui só para exemplicar o uso de um outro try
            //ele não tem nada haver com a captura do denominador errado
        }
        Fracao f2(2, 0);
    } catch(RunnableException re) {
        //esse catch vai pegar o denominador errado
        std::cout << t.getMessage() << std::endl;
    }
}
    
29.09.2016 / 15:00