Home > Enterprise >  Throw object vs throw variable as exception in c oop
Throw object vs throw variable as exception in c oop

Time:12-09

I have been reading a book where the object oriented implementation for exceptions is as follows:

Rectangle.hpp

class Rectangle
{
private:
    // code

public:
    class NegativeSize
    {
        // empty class declaration
        // for exception
    };

    // code
};

Whenever a specific error occurs, the NegativeSize() is thrown from the constructor as follows:

Rectangle.cpp

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        // this instantiates an object
        throw NegativeSize();
    }

    x = _x;
}

main.cpp

    try
    {
        // code
    }
    catch (Rectangle::NegativeSize)
    {
        cout << "Negative value entered" << endl;
    }

But I can do the same thing by declaring a public variable in Rectangle class and throw it instead:

Rectangle.hpp

class Rectangle
{
private:
    // code

public:
    string NegativeVal;

    // code
};

Rectangle.cpp

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        throw NegativeSize;
    }

    x = _x;
}

main.cpp

    try
    {
        // code
    }
    catch (string NegativeSize)
    {
        cout << "Negative value entered" << endl;
    }

Can the second implementation be considered a good practice?

CodePudding user response:

The actual exception object that the catch clause will catch is not the object that you name or refer to in the throw expression. Instead the exception object is an object of the same (decayed) type as the throw operand and initialized from the same.

So in your first example you throw an object of type Rectangle::NegativeSize which is initialized from NegativeSize() and in the second example you throw a std::string which is a copy of the NegativeSize member, whatever value it holds at that time.

In the second example catch (Rectangle::NegativeSize) will not work, because NegativeSize is not a type anymore. You will need to catch std::string instead, which of course is a problem, since it doesn't tell you at all what the kind of exception this is (plus some other deeper issues).

Throwing a std::string instead of a specific exception class is therefore not a good practice. You wouldn't be able to differentiate different exceptions and catch only those you can handle in a given catch clause.

Throwing a data member also seems pointless. What value will you set it to? Probably just the "Negative value entered" string? If so, that could be thrown directly as throw std::string("Negative value entered"); as well. As I said above, the exception object is going to be a copy anyway. At the catch clause you can't identify anymore that the throw expression used the NegativeSize member.

Also, in practice exception classes are usually derived from std::exception or a class derived from it and are not empty. They commonly store a string which can be given at the point of the throw expression, so that detailed information from the source of the exception can be provided to the user, e.g.:

class Rectangle
{
private:
    // code

public:
    struct NegativeSize : std::invalid_argument {};

    // code
};

//...

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        throw NegativeSize("Negative value entered");
    }

    x = _x;
}

//...

try
{
    // code
}
catch (const Rectangle::NegativeSize& e)
{
    cout << e.what() << endl;
}

Also, as I do above, exceptions should usually be caught by-reference.

  • Related