Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it OK to store information regarding an error in an Exception object?

Tags:

c++

exception

I've been reading about exceptions in C++, the pros and cons, and I've yet to encounter anyone mention the two things I really like about them: They allow me to extend the definition of an error (to something that is more than just an error message as a string), and, they allow me to define a contract between the exception handler and the thrower:

"If I'm going to handle this particular type of error, I'm going to need this, this and that from you."

I've not seen this mentioned in any of the articles, forums and blog posts, as a pro or a con. And that has made me suspect that my mindset on exceptions and how they should be used may be wrong.

To clarify, here's an example of my usage of exceptions:

A program communicates with a USB device (it sends commands to the device and expects a certain response from it). This USB device can sometimes behave in an unexpected way when responding to a command. In this case, the program will throw an UnexpectedResponseFromDevice exception. The handler for this exception needs more than just an error message in order to do its job. For example, it may need to know of the command that we were sending to the device when the error occurred, and/or the state the device was in. I use the definition of my UnexpectedResponseFromDevice class to explicitly set out what is required to handle the exception. See below for a rough idea.

class UnexpectedResponseFromDevice : public std::exception
{
private:
    Command command;
    DeviceState deviceState;
    std::string msg;

public:
    UnexpectedResponseFromDevice(std::string msg, Command command, DeviceState deviceState, ...)
    Command getCommand();
    DeviceState getDeviceState();
};

This is what I meant by "define a contract between the exception handler and the thrower". In order to throw the exception, these things (in this case a Command, a DeviceState and a message) need to be provided.

Is this an acceptable use case for exceptions? Is it OK for me to store this other information, that is required for the handling of the exception, in the exception object? Is it acceptable but a bad idea? If so, please explain why.

like image 606
John O'brien Avatar asked Apr 19 '20 22:04

John O'brien


People also ask

What happens when an exception object is not caught and handled properly?

What happens if an exception is not caught? If an exception is not caught (with a catch block), the runtime system will abort the program (i.e. crash) and an exception message will print to the console.

Which of the following should not throw an exception?

I also know that the following cannot throw exceptions either: Destructors. Reading/writing primitive types.

What is an exception object?

When an error occurs within a method, the method creates an object and hands it off to the runtime system. The object, called an exception object, contains information about the error, including its type and the state of the program when the error occurred.

What is the difference between error and exception?

Both exceptions and errors are the subclasses of a throwable class. The error implies a problem that mostly arises due to the shortage of system resources. On the other hand, the exceptions occur during runtime and compile time.


1 Answers

Is this an acceptable use case for exceptions? Is it OK for me to store this other information, that is required for the handling of the exception, in the exception object?

Yes, that's how the exceptions in the standard library do too. One example is std::system_error that derives from std::runtime_error but adds a std::error_code member to carry extra information. One that adds a lot more is std::filesystem::filesystem_error that adds two std::filesystem::path objects.

Is it acceptable but a bad idea? If so, please explain why.

It's only a bad idea if you risk throwing another exception (like a std::bad_alloc) while throwing your exception - or if you use exceptions as something else than exceptions, like choosing between common branches in your program flow. Throwing should preferably be a rare event.

If your have all the info you need in a std::string, or even in something like a std::stack<std::string>>, member variable in the object that is a about to throw you can probably std::move that member object into the exception object to minimize the risk - if you don't need that data anymore in the object that is throwing that is.

I don't know how big your std::string, Command and DeviceState objects are, but you may not want to construct the exception object by taking the parameters by value. Try to make construction noexcept. The getters should also probably return by const&. That's not as critical - but making them so minimizes the risk of an exception in your exception handler.

like image 143
Ted Lyngmo Avatar answered Nov 14 '22 03:11

Ted Lyngmo