Is std::bad_optional_access a small crime against exceptions? - c++

If std::optional's value() member function is called when the optional has no actual value initialized, a std::bad_optional_access is thrown. As it is derived directly from std::exception, you need either catch (std::bad_optional_access const&) or catch (std::exception const&) for dealing with the exception. However, both options seem sad to me:
std::exception catches every single exception
std::bad_optional_access exposes implementation details. Consider the following example:
Placement Item::get_placement() const {
// throws if the item cannot be equipped
return this->placement_optional.value();
}
void Unit::equip_item(Item acquisition) {
// lets the exception go further if it occurs
this->body[acquisition.get_placement()] = acquisition;
}
// somewhere far away:
try {
unit.equip_item(item);
} catch (std::bad_optional_access const& exception) { // what is this??
inform_client(exception.what());
}
So, to catch the exception you need to be well-informed about the usage of std::optional in the Item's implementation, being led to a list of already known issues. Neither I want to catch and rewrap std::bad_optional_access because (for me) the key part of exceptions is the possibility of ignoring them until needed. This is how I see the right approach:
std::exception
<- std::logic_error
<- std::wrong_state (doesn't really exist)
<- std::bad_optional_access (isn't really here)
So, the "far away" example could be written like this:
try {
unit.equip_item(item);
} catch (std::wrong_state const& exception) { // no implementation details
inform_client(exception.what());
}
Finally,
Why is std::bad_optional_access designed like it is?
Do I feel exceptions correctly? I mean, were they introduced for such usage?
Note: boost::bad_optional_access derives from std::logic_error. Nice!
Note 2: I know about catch (...) and throwing objects of types other than std::exception family. They were omitted for brevity (and sanity).
Update: unfortunately, I can't accept two answers, so: if you're interested in the topic, you can read Zuodian Hu's answer and their comments.

You say that the key appeal of exceptions is that you can ignore them for as deep of a call stack as you can. Presumably, given your ambition of avoiding to leak implementation details, you no longer can let an exception propagate beyond the point where that exception cannot be understood and fixed by its handler. That seems to be a contradiction with your ideal design: it punts fixing the exception to the user, but bad_optional_access::what has exactly no context on what just happened–leaking implementation details to the user. How do you expect a user to take meaningful action against a failure to equip an item when all they see is, at best, "could not equip item: bad_optional_access"?
You have obviously made an over-simplification, but the challenge remains. Even with a "better" exception hierarchy, std::bad_optional_access simply does not have enough context that anything beyond extremely close callers might know what to do with it.
There are several fairly distinct cases in which you might want to throw:
You want control flow to be interrupted without much syntactical overhead. For instance, you have 25 different optionals that you want to unwrap, and you want to return a special value if any of them fails. You put a try-catch block around the 25 accesses, saving yourself 25 if blocks.
You have written a library for general use that does a lot of things that can go wrong, and you want to report fine-grained errors to the calling program to give it the best chance of programmatically doing something smart to recover.
You have written a large framework that performs very high-level tasks, such that you expect that usually, the only reasonable outcome of an operation failing is to inform the user that the operation has failed.
When you run into issues with exceptions not feeling right, it's usually because you're trying to handle an error meant for a different level than the one you wish it was operating at. Wishing for changes to the exception hierarchy is just trying to bring that exception in line for your specific use, which causes tensions with how other people use it.
Clearly, the C++ committee believes that bad_optional_access belongs to the first category, and you're asking why it's not part of the third category. Instead of trying to ignore exceptions until you "need" to do something with them, I believe that you should flip the question around and ask yourself what is intended to catch the exception.
If the answer truly is "the user", then you should throw something that's not a bad_optional_access and that instead has high-level features like localized error messages and enough data on it that inform_user is able to bring up a dialog with a meaningful title, main text, subtext, buttons, an icon, etc.
If the answer is that this is a general game engine error and that it might happen in the regular course of the game, then you should throw something that says that equipping the item failed, not that there was a state error. It's more likely that you'll be able to recover from failing to equip an item than from having a non-descript state error, including if, down the road, you need to produce a pretty error for the user.
If the answer is that you might try to equip 25 items in a row and you want to stop as soon as something goes wrong, then you need no changes to bad_optional_access.
Also note that different implementations make different uses more or less convenient. In most modern C++ implementations, there is no performance overhead on code paths that do not throw, and a huge overhead on paths that do throw. This often pushes against the use of exceptions for the first category of errors.

So, to catch the exception you need to be well-informed about the usage of std::optional in the Item's implementation
No, to catch the exception, you must read the documentation for get_placement, which will tell you that it throws std::bad_optional_access. By choosing to emit that exception, the function is making the emission of that exception a part of the interface of that function.
And therefore, it is no more dependent on Item's implementation than it would be if it directly returned a std::optional. You choose to put it in your interface, so you ought to live with the consequences.
To put it another way, if you felt that putting std::optional as a parameter type or return value was wrong, then you should feel the same way about emitting bad_optional_exception directly.
Ultimately, this all goes back to one of the most fundamental questions of error handling: how far away from the site of the error can you get before the specific nature of the error becomes effectively meaningless or even completely different?
Let's say you're doing text processing. You've got a file with each line containing 3 floating-point numbers. You're processing it line by line, and inserting each set of three values into a list. And you have a function that converts strings to floats, which throws an exception if that conversion fails.
So the code broadly looks like this:
for each line
split the line into a 3-element list of number strings.
for each number string
convert the string into a number.
add the number to the current element.
push the element into the list.
Alright, so... what happens if your string-to-float converter throws? That depends; what do you want to happen? That's determined by who catches it. If you want a default value on an error, then the code in the innermost loop catches it and writes a default value into the element.
But maybe you want to log that a particular line has an error, then skip that line (don't add it to the list), but continue processing the rest of the text as normal. In that case, you catch the exception in the first loop.
At that point, the meaning of the error has changed. The error which was thrown was "this string doesn't contain a valid float", but that's not how your code handles it. In fact, the catching code has completely lost the context of the error. It doesn't know whether it was the first, second, or third string in the text which caused the failure. At best, it knows that it was somewhere along that line, and maybe the exception happens to contain a couple of pointers to the bad string range (though that's increasingly dangerous the farther that exception gets from its source, due to the possibility of dangling pointers).
And what if a failed conversion ought to mean that the entire process can no longer be trusted, that the list you're building is invalid and should be discarded? This has even less context than the previous case, and the meaning is even more muddled and distant. At this point, the error just means to terminate the list building process. Maybe you put together a log entry, but that's about all you're going to do at this point.
The farther you get from where the exception is thrown, the more context about the error is lost, and the more the meaning ultimately drifts from the initial meaning of the error. That's not just about being an implementation detail; it's about the locality of information and the response to that information.
So basically, code close to the source of the error is catching specific exceptions with contextual meaning. The farther the catch gets from the source of the error, the more likely it is that the catching code is going to be very generic, dealing with vague "this didn't work because reasons" kinds of things. This is where vague types like std::logic_error come in.
Indeed, one could imagine that at each step in the process, the exception is reinterpreted (and by "reinterpreted", I mean converting it into a different type via catch/throw). The string-to-float converter throws a meaningful exception: could not convert string to float. The layer trying to build an element from 3 strings converts the exception to something that has value to its caller: string index X is malformed. And at the last phase, the exception is generalized to: couldn't parse the list due to line Y.
The idea that a single exception type can jump through whole libraries of code and designed intent and still retain its initial meaning is a fantasy. Exceptions work great when they have to pass through neutral code, such as throwing an exception from a callback or some other case of indirect function execution. In this case, the code which provoked the execution still has the local context of the process that provoked the exception. But the farther from the local context who knows what's going on you get, the less meaningful a specific exception becomes.
Inheriting from logic_error is wrong for these reasons. Catching a bad_optional_access is ultimately a very local thing. Past a certain point, the meaning of that error changes.
A "logic error" represents a failure of your program to make sense. But an optional which doesn't contain a value does not necessarily represent such a problem. In one piece of code, it could be a perfectly valid thing to have an empty optional, and the exception being thrown is simply how that gets reported to the caller. Another piece of code might treat an optional being empty at a certain point as a user having made some prior mistake in their API usage. One of these is a logic error, and the other isn't.
Ultimately, the right thing to do is make sure that your classes APIs all emit exceptions which are meaningful to the caller. And it's not clear what bad_optional_access means to the caller of get_placement.

Exposing Implementation Details
If you wish for your user to be entirely unaware of std::optional in your implementation, your interface would either check operator bool or has_value and do one of the following:
return a status code
throw a custom exception type
handle the emptiness in such a way that the client has no knowledge that an internal error ever happened
...or your interface would catch std::bad_optional_access and do one of the above. In either case, your client has no idea you used std::optional.
Note that whether you found out about the emptiness of the optional through an explicit check or an exception is a design choice (but personally I wouldn't catch and re-throw either in most cases).
Logic Error?
Based on the conceptual model for optional in the pre-standardization paper, std::optional is a value wrapper with a valid empty state. Hence, the intent was for emptiness to be intentional in normal usage. There are two general ways handling emptiness, as I stated in the comments:
use operator bool or has_value, then handle emptiness inline or use the wrapped value through operator* or operator->.
use value and bail out of the scope if the optional is empty
In either case, you should be expecting the optional to potentially be empty, and designed for that to be a valid state in your program.
In other words, when you use operator bool or has_value to check for emptiness, it is not to prevent an exception being thrown. Instead, you are choosing to not use the exception interface of optional at all (usually). And when you use value, you are choosing to accept optional potentially throwing std::bad_optional_access. Hence, the exception should never be a logic error in the intended usage of optional.
UPDATE
Logic Errors in the Design of C++
You seem to misunderstand the Standard's intended definition of what a logic error is.
In the design of C++ in recent years (not the same in history), a logic error is a programmer error the application shouldn't try to recover from because it can't reasonably recover. This includes things like de-referencing dangling pointers and references, using operator* or operator-> on an empty optional, passing invalid arguments to a function, or otherwise breaking API contracts. Note that dangling pointers' existence is not a logic error, but de-referencing a dangling pointer is a logic error.
In these cases of true logic errors, the Standard purposely chooses not to throw because they are true logic errors on the part of the programmer, and the caller can't be reasonably expected to handle all bugs in the code they call.
When a well-designed (under this philosophy) Standard Library function throws, it's never supposed to be because the code or the caller wrote buggy code. For buggy code, the Standard let's you fall flat on your face for writing the bug. For example, many functions in <algorithn> run infinite loops if you pass them bad begin and end iterators, and never even try to diagnose the fact that you did that. They certainly don't throw std::invalid_argument. "Good" implementations do try to diagnose this in Debug builds though, because those logic errors are bugs. When a well-designed (under this philosophy) Standard Library function throws, it's supposed to be because a truly exceptional and unavoidable event occurred. has many throwing functions, because you can't really ever know for sure what's on some random file system. That's the situation exceptions are supposed to be used for.
In the paper linked below, Herb Sutter speaks against std::logic_error's existence as an exception type for this very reason. Clearly stating the philosophy, catching std::logic_error or any of its children amounts to introducing runtime overhead to fix programmer logic bugs. Any true logic error condition you want to detect should be asserted on, really, so the bug can be reported back to the people who wrote the bug.
In the optional interface, designed with the above in mind, value throws so that you can programmatically deal with it in a sensible way with the expectation that whoever catches it either don't care what bad_optional_access means (catch( ... ) // catch everything) or can specifically deal with bad_optional_access. That exception really isn't meant to propagate far at all. When you purposely call value, you do so because you acknowledge the optional may be empty, and you choose to exit the current scope if it does turn out to be empty.
See the first section of this paper (download) for the philosophical rationale.

First, if you don't want to expose the imlementation, than the exceptions shouldn't even cross the border between the implementation and the client code. This is a common idiom that no exception should cross the boundaries of libraries, APIs, etc.
Next, the fact that you store something in an optional is the implementation that you should control by yourself. That means that you should check that the optional is not empty (at least if you don't want the client knowing the details of the implementation).
And finally, answer the question: is it an error that the client code performs an operation on an empty object? If that is something that it is allowed to do, than no exception should be thrown (e.g. error code may be returned). If that is a real problem that shouldn't happen, throwing an exception is appropriate. You may catch the std::bad_optional_access in your code and throw something else from the catch block.

Another solution to your problem could be nested exceptions. That means that you catch a lower level exception (in your case std::bad_optional_access) and then throw another exception (of any type, in your case you may implement a wrong_state : public std::logic_error) using the std::throw_with_nested function. Using this approach you:
Preserve the information about the lower level exception (it is
still stored as a nested exception)
Hide this information about the nested exception from the user
Allow user to catch the exception as a wrong_state or a std::logic_error.
see the example: https://coliru.stacked-crooked.com/view?id=b9bc940f2cc6d8a3

Consider this REAL WORLD example of when NOT to use std:bad_optional_access, involving the INELEGANT 900 lines of code, wrapped up into one HUGE class, just to render a vulkan triangle, in THIS example at https://vulkan-tutorial.com/code/06_swap_chain_creation.cpp
I am in the process of reimplementing the one HUGE HelloTriangleApplication class into multiple smaller classes. And,the QueueFamilyIndices struct begins as a couple of empty std::optional<uinit32_t> lists , ergo, EXACTLY the sort of not-yet-a-things which std::optional was invented to handle.
So, obviously, I wanted to test each class, before subclassing it into another class. But, this involved leaving some not-yet-a-things uninitialized until a parent's subclass was latter implemented.
It seemed right, at least to me, NOT to use std:bad-optional-access as a placeholder for future values, but rather to just code a 0 in the parent class, as a placeholder for not yet implemented std:optional not-yet-a-things. Which was enough to avoid my IDE reporting those annoying "bad optional access" warnings.

This is a good question with good answers. I want to highlight some of the main points more directly, and also add some points that I disagree with from the other answers. I come at this more from the POV of abstract flow of information, with the idea that all infinite variants of specific situations become easier to handle when appropriate information is passed around effectively.
The TL;DR here is:
Using bad_optional_access in a semantically incorrect way is common, but is the root cause of a lot of the other stuff (like logic_error) appearing to not making sense, and
value() should be used only when you know it has a value; it's not intended as some "exception-y" variation of value_or(). It doesn't make sense when there is no value: A thing with no value does not have a value, and so retrieving its value isn't something you can do. If you call 'value()' when there's no value then you made a mistake somewhere.
Regarding the use of value() itself:
If you cannot guarantee that an optional has a value, you use has_value() or value_or(). The use of value() assumes the optional has a value and by using it, you are stating that assumption as an invariant (i.e. assert(x.has_value()) is expected to pass), and if it doesn't have a value, then the invariant has been violated and an exception is appropriate. value() does not have meaning when the optional doesn't have a value. It is the same reason that you do not compute a / b in situations where b might be 0 -- you either know it isn't 0, or you check first. Likewise dereferencing invalid iterators, accessing invalid pointers, calling front() on an empty container, uh... computing the unbiased variance of a single sample... things like that.
Following that point, if you see a bad_optional_access, then this means there is a bug in your code: one of your assumptions (it had a value) was false. In other words, this is a development error, and in an ideal world a user should never encounter this exception in the same way a user should never encounter an assertion failure or a divide-by-zero or a null pointer access: It does not represent a user-actionable error, it represents code that needs to be fixed. Ideally only you as a developer should encounter this particular exception.
This is specifically why it is a logic_error: You used value() but did not honor its preconditions, and the implied assumption that you made about it having a value was not correct. You made a programming error by using value() in a situation where you could not guarantee that it had a value.
That said, the world isn't ideal. Also, generally speaking, if some exception below some layer of code is meant to represent a more user-appropriate error above that layer of code, then you need to translate that exception. For example:
An exception may expose an implementation detail that you want to abstract away.
An exception may contain information that doesn't make sense to a user, but may represent a larger more generic issue that is important to a user.
And so you need to translate that. For example:
Placement Item::get_placement() const {
// throws if the item cannot be equipped
return this->placement_optional.value();
}
The comment literally says "throws if the item cannot be equipped", but bad_optional_access doesn't mean "an item cannot be equipped". So if you allow it to be thrown out of that function, then you've miscommunicated the conceptual issue by throwing a semantically incorrect exception. Instead:
// elsewhere
class item_equip_exception : ... {
...
};
// then:
Placement Item::get_placement() const {
// throws if the item cannot be equipped
try {
return this->placement_optional.value();
} catch (const std::bad_optional_access &x) {
throw item_equip_exception(...);
}
}
Because that's what you're really trying to communicate.
However, an even more correct version of that would be:
Placement Item::get_placement() const {
// throws if the item cannot be equipped
if (!this->placement_optional.has_value())
throw item_equip_exception(...);
return this->placement_optional.value();
}
The reason this is more correct is because now you are calling value() in a situation where your assumption that it has a value should be guaranteed. And in this case, if you end up with a bad_optional_access, then it's truly a serious logic error. This now means that, as long as you're consistent with this approach, at the very top level of your application you can now actually catch std::logic_error and it really will mean that some program logic went terribly wrong, and you can inform the user as such.
All of the issues in the original post can basically be boiled down to semantics:
If you use value() when there might be no value, that's a programming error, and...
If you then use that "programming error" to signify a general user-facing error, then...
... you've now tangled up all the semantics and nothing makes sense any more, including `std::logic_error'.
Where on the other hand:
If there reasonably may be no value and that signifies some higher level thing like "the item can't be equipped", and...
You check for that and throw a more appropriate exception and never call value() when there's no value, then...
... you can now communicate that to the user, the logic_error -> bad_optional_access inheritance meaning continues to make sense, and you can still separately catch programmer errors at a higher level.
So yeah; "say what you mean" applies as much to information flow in programming as it does to speaking in real life!

Related

Using throw to replace return in C++ non-void functions

In C++ functions, is it a good practice to replace return with throw? For example, I have the following code
// return indices of two numbers whose sum is equal to target
vector<int> twoSum(vector<int>& nums, int target) {
for(int i=0; i<nums.size()-1; ++i)
for(int j=i+1; j<nums.size(); ++j)
{
if(nums[i] + nums[j] == target) return vector<int>{i, j};
}
// return vector<int>{};
throw "no solution";
}
The code above compiles with my GCC 7.2.
In C++ functions, is it a good practice to replace return with throw?
Return is not something that can be replaced by a throw in general.
In exceptional cases where you have nothing to return, throwing an exception can be a valid way to exit the function.
Whether it is "good practice", and what case is "exceptional" are subjective. For example, for a search function such as yours, it's hardly a surprise that there might not be a solution, and I would argue that throwing would not be appropriate.
There are often other alternatives to throwing. Compare your algorithm with something like std::string::find that returns the index of the start of a substring. In case where substring does not exist, it returns a "non-value" std::string::npos. You could do the same and decide that the index -1 is returned when a result is not found. There is also a generic way to add non-value representation to a type in cases where none of the existing representations can be reserved for the purpose: std::optional.
P.S. A vector is probably not a good choice for returning a pair of numbers. std::pair might be better, or a custom class if you have good names for the numbers.
The concepts of this answer are taken from the C++ Programming language by Bjarne Stroustrup.
SHORT ANSWER
Yes, exception-throwing can be used as returning value method. An example is the following for a binary tree search function:
void fnd(Tree∗ p, const string& s)
{
if (s == p−>str) throw p; // found s
if (p−>left) fnd(p−>left,s);
if (p−>right) fnd(p−>right,s);
}
Tree∗ find(Tree∗ p, const string& s)
{
try {
fnd(p,s);
}
catch (Tree∗ q) {
// q->str==s
return q;
}
return 0;
}
However, it should be avoided because:
they allow you to separate error code from "ordinary code" making your program much more readable, comprehensible and manageable. If you use them as return method, this does not hold anymore.
there might be inefficiencies because exception implementations rely on the assumption that they are used as error-handling methods.
Apart from that, there are further limitations:
exceptions must be of copy-able type
exceptions can handle only synchronous events
they should be avoided in a time-critical system
they should be avoided in large old programs in which resource management is an ad hoc mess (free store is unsystematically managed using naked pointers, news and delete) rather than relying on some systematic scheme such as resource handles (strings vectors).
Longer answer
An exception is an object thrown to represent the occurrence of an error. It can be of any type that can be copied but it is strongly recommended to use only user-defined types specifically defined for that purpose. Exceptions allow the programmer to explicitly separate error-handling code from "ordinary code" making the program more readable.
First of all, exceptions are for managing synchronous events, not asynchronous ones. This is one first limitation.
One might think of the exception-handling mechanisms as simply another control structure, an alternative way of returning a value to a caller.
This has some charm but should be avoided because it is likely to cause confusion and inefficiencies. Stroustrup suggests:
When at all possible stick to the "exception handling is an error
handling" view. When this is done code is separated into two categories:
ordinary code and error handling code. This makes the code more
comprehensible. Furthermore, the implementations of the exception
mechanisms are optimized based on the assumption that this simple
model underlies the use of the exception.
So basically using exceptions to return value should be avoided because
exception implementation is optimized assuming they are used for error-handling and not for returning values hence they might be inefficient for that;
They allow separating error code from ordinary code making the code much more readable and comprehensible. Anything that helps preserve a clear model of what is an error and how it is handled should be treasured.
There are programs that for practical or historical reasons cannot use exceptions (neither as error handling so even less):
A time-critical component of an embedded system where operation must be guaranteed to complete in a specified maximum time. In the absence of tools that can accurately estimate the maximum time for an exception to propagate from throw to catch alternative error handling methods must be used.
A large old program in which resource management is an ad hoc mess (free store is unsystematically managed using naked pointers, news and delete) rather than relying on some systematic scheme such as resource handles (strings vectors).
In the above cases, traditional pre-exception methods are preferred.
return and throw have two different purposes and should not be considered interchangeable. Use return when you have a valid result to send back to the caller. On the other hand, use throw when some exceptional behavior occurs. You can get an idea of how other programmers use throw by using functions from the standard library and taking note of when they throw exceptions.
In addition to the other answers, there's also performance: Catching an exception incurs a run-time overhead (see this answer) compared to an if clause.
(Of course, we're talking about microseconds... Whether or not this is relevant depends on your specific use case.)
A function should throw an exception when it is unable to meet its postcondition. (Some functions may also throw exceptions when their preconditions are not met; that's a different topic that I won't get into here.) Therefore, if your function must return a pair of integers from the vector summing to the given target, then it has no choice but to throw an exception when it can't find one. But if the function's contract allows it to return a value to indicate it was unable to find such a pair, then it should not throw an exception, since it has the ability to fulfill the contract.
In your case:
You can make your function return an empty vector when it can't find two integers summing to the given target. Then, it never needs to throw an exception.
Or, you can make your function return std::optional<std::pair<int, int>>. It never needs to throw an exception because it can just return an empty optional when it can't find an appropriate pair.
If, however, you make it return std::pair<int, int>, then it should throw an exception because there is no sensible value to return when it can't find an appropriate pair.
Generally, C++ programmers prefer to write functions that don't need to throw exceptions in order to report mere "disappointments", such as search failures, that are easily anticipated and handled locally. The advantages of returning values rather than throwing exceptions are discussed extensively elsewhere so I won't rehash that discussion here.
Thus, declaring "failure" by throwing an exception is usually limited to the following cases:
The function is a constructor and it's simply not able to establish its class's invariant. It must throw an exception in order to ensure that the calling code doesn't see a broken object.
An "exceptional" condition arises that should be handled at some higher level than that of the caller. The caller is likely to not know how to recover from the condition. In such cases, the use of the exception mechanism frees up the caller from having to figure out how to proceed when the exceptional condition occurs.
What you have mentioned is not good programming practice. Replacing a return statement with throw is not acceptable in production-level code, especially with automated testing platforms that generate lists of all exceptions as a way of proving or disproving certain functionality. You have to take into consideration the needs of Software Testers when designing your code. throw is simply not interchangeable with return. throw is used to signal that a program error has occurred by some unexpected phenomena. return is used to signal method completion. It is common to use return to transmit error codes, but return values do not cause the program to be interrupted in the same way as throw does. Additionally, throw has the power to terminate a program if it is not handled correctly.
Essentially, it is good practice to use throw when a significant error is detected within the method, but there should always be a clean return if such an error is not detected. Can you make that substitution? Maybe, and maybe it will work logically...but it's not good practice and certainly not a popular implementation.
No, throw is not a good semantic replacement for return. You only want to use throw when your code has done something that it should not be doing, not to signify the perfectly valid negative result of a function.
As a general rule, exceptions are meant to signify when something abnormal or unexpected has happened during the execution of your code. Looking at the purpose of your function, the occurrence of no two integers in the passed vector summing to target is a very possible result of the function, so that result is not abnormal and thus should not be treated as exceptional.
Just because the function is throwing as the last call, doesn't mean it is replacing return. It is just the flow of logic.
The question shouldn't be :
is it a good practice to replace return with throw?
Instead it should be about : how to define your API and contracts.
If You want to guarantee to the users of the function that vector is never empty, then throwing an exception is a good idea.
If you want to guarantee that your function doesn't throw exceptions instead returns an empty vector on certain conditions, then throwing is a bad idea.
In both cases, the user has to know, what actions they have to take to correctly use your function.
Your question is language agnostic.
Return and Throw have different purposes.
Return is for returning a value; while,
Throw is for throwing an exception; and,
An exception should be thrown in truly exceptional conditions.
Bonus Content (from Steve McConnell’s Code Complete 2)
Here are all the alternatives available to you when you encounter a situation where you cannot return normally:
Return a neutral value like -1 from a method that’s supposed to return count of something;
Return the closest legal value like 0 on the digital speedometer of a car when it is going in reverse;
Return same value as previous call like a temperature reading on a thermometer when you are reading every second and you know that the readings do not differ drastically in such a short interval;
Return the next valid piece of data like when you are reading rows from a table and a specific row is corrupt;
Set/Return an error status/code/object found pretty commonly in C++ library calls;
Display a message in an alert box but be careful to not give out too much that can assist a malicious actor;
Log to a file;
Throw an exception like you are pondering upon;
Call a central error handler/routine if that is how your system is designed;
Shutdown.
Further, you do not need to pick only one of the above options. You can do a combination like, for example, logging to file and displaying a message to the user.
What approach you should take is a question of Correctness vs Robustness. Do you want your program to be absolutely correct and shutdown when an erroneous situation is encountered or do you want your program to be robust and continue with execution when at some point it fails to follow the desired path?
I think it is the wrong question asking if return can be replaced by throw. return and throw are doing two very different things:
return is used to return regular results of a functions.
throw is the preferred method to react on error conditions when a result value does not exist.
The alternative reaction on errors could be to return special error code values. This has some disadvantages, e.g.:
Using a function gets more difficult if you always have to keep error codes etc. in mind.
The caller might forget to handle the error. When you forget an exception handler, you will get unhandled exception. It is very likely that you will detect this bug.
The error might be too complex to be expressed by a single error code properly. An exception can be an object containing all the information you need.
The errors are handled at a well-defined position (the exception handler). This will make your code much clearer than checking the return value for special values after each call.
In your example the answer depends on the semantics of the function:
If an empty vector is an acceptable return value, then you should use return if no pair is found.
If it is expected that there MUST be matching pairs always, then finding no pair obviously is an error. You should use throw in this case.

Not sure when to use exceptions in C++

After many years of coding scientific software in C++, I still can't seem to get used to exceptions and I've no idea when I should use them. I know that using them for controlling program flow is a big no-no, but otherwise than that... consider the following example (excerpt from a class that represents an image mask and lets the user add areas to it as polygons):
class ImageMask
{
public:
ImageMask() {}
ImageMask(const Size2DI &imgSize);
void addPolygon(const PolygonI &polygon);
protected:
Size2DI imgSize_;
std::vector<PolygonI> polygons_;
};
The default constructor for this class creates a useless instance, with an undefined image size. I don't want the user to be able to add polygons to such an object. But I'm not sure how to handle that situation. When the size is undefined, and addPolygon() is called, should I:
Silently return,
assert(imgSize_.valid) to detect violations in code using this class and fix them before a release,
throw an exception?
Most of the time I go either with 1) or 2) (depending on my mood), because it seems to me exceptions are costly, messy and simply overkill for such a simple scenario. Some insight please?
The general rule is that you throw an exception when you cannot perform the desired operation. So in your case, yes, it does make sense to throw an exception when addPolygon is called and the size is undefined or inconsistent.
Silently returning is almost always the wrong thing to do. assert is not a good error-handling technique (it is more of a design/documentation technique).
However, in your case a redesign of the interface to make an error condition impossible or unlikely may be better. For example, something like this:
class ImageMask
{
public:
// Constructor requires collection of polygons and size.
// Neither can be changed after construction.
ImageMask(std::vector<PolygonI>& polygons, size_t size);
}
or like this
class ImageMask
{
public:
class Builder
{
public:
Builder();
void addPolygon();
};
ImageMask(const Builder& builder);
}
// used like this
ImageMask::Builder builder;
builder.addPolygon(polyA);
builder.addPolygon(polyB);
ImageMask mask(builder);
I would try to avoid any situation where it's possible to create data that is in some kind of useless state. If you need a polygon that is not empty, than don't let empty polygons be created and you save yourself much trouble because the compiler will enforce that there are no empty polygons.
I never use silent returns, because they hide bugs and this makes finding bugs much more complicated than it have to be.
I use asserts when I detect that the program is in a state that it only can be in, if there is a bug in the software. In your example, if you check in the c'tor that takes a Size2DI, that this size is not empty, than asserting if the size stored is not empty, is useful to detect bugs. Asserts should not have side effect and it must be possible to remove them, without changing the behavior of the software. I find them very useful, to find my own bugs and to document, the current state of the object / function etc.
If it's very likely, that a runtime error will be handled directly by a caller of a function, I would use conventional return values. If it's very likely, that this error situation have to be communicated over several function calls at the call stack, I prefer exceptions. In doubt I offer two function.
kind regards
Torsten
To me, 1 is a no option. Whether it is 2 or 3 depends on the design of your program/library, whether you consider (and document) default-constructing image mask and then adding polygons a valid or invalid usage of your component. This is an important design decision. I recommend reading this article by Matthew Wilson.
Note that you have more options:
Invent your own assert that always calls std::terminate and does additional logging
Disable the default constructor (as others already pointed out) -- this is my favourite
"Silently return" - that's real 'the big no-no'. The program should know what's wrong.
"assert" - the second rule is that asserts using only if normal program's flow couldn't be restored.
"throw exception" - yes, this right and good technique. Just take care about exception-safety. There are many articles about exception-safe coding on GotW.
Don't afraid exceptions. They don't bite. :) If you'll take this technique enough, you'll be a strong coder. ;)

Whats the right approach for error handling in C++

One is to use C++ exceptions: try catch blocks. But freeing dynamic memory will be an issue when an exception is raised.
Second is to use C style: errno variable
Third is just to return -1 on error and 0 on success :)
Which way should be chosen for a mid-size project and why? Any other better approach..?
But freeing dynamic memory will be an issue when an exception is raised.
No it's not. std::vector<int> v(100); Done.
The concept here is called Scope-Bound Resource Management (SBRM), also known by the much more common (and awkward) name Resource Acquisition Is Initialization (RAII). Basically, all resources are contained in some object which will clean up the resource in the destructor (which is always guaranteed to be run for an automatically allocated object). So whether or not the function exists normally or via exception, the destructor is run and your resource is cleaned up.
Never do an allocation where you need to free it explicitly, use containers and smart pointers.
Second is to use C style: errno variable
Third is just to return -1 on error and 0 on success :)
And how do they help solving your problem of freeing dynamic memory? They also use an early-exit strategy, same as throw.
So in summary, they don’t have an advantage over C++ exceptions (according to you).
In the first place, you should strive for a program with minimum error cases. (Because errors are not cool.)
Exceptions are a nice tool but should be used conservatively: reserve them for "exceptional cases", do not use them to control the flow of your program.
For example, do not use exceptions to test whether a user input is correct or not. (For such a case, return an error code.)
One is to use C++ exceptions: try
catch blocks. But freeing dynamic
memory will be an issue when an
exception is raised.
#see RAII.
Exceptions should be your preferred method of dealing with exceptional runtime situations like running out of memory. Note that something like std::map::find doesn't throw (and it shouldn't) because it's not necessarily an error or particularly exceptional case to search for a key that doesn't exist: the function can inform the client whether or not the key exists. It's not like a violation of a pre-condition or post-condition like requiring a file to exist for a program to operate correctly and finding that the file isn't there.
The beauty of exception-handling, if you do it correctly (again, #see RAII), is that it avoids the need to litter error-handling code throughout your system.
Let's consider a case where function A calls function B which calls C then D and so on, all the way up to 'Z'. Z is the only function that can throw, and A is the only one interested in recovering from an error (A is the entry point for a high-level operation, e.g., like loading an image). If you stick to RAII which will be helpful for more than exception-handling, then you only need to put a line of code in Z to throw an exception and a little try/catch block in A to catch the exception and, say, display an error message to the user.
Unfortunately a lot of people don't adhere to RAII as strictly as they should in practice, so a lot of real world code has more try/catch blocks than should be necessary to deal with manual resource cleanup (which shouldn't have to be manual). Nevertheless, this is the ideal you should strive to achieve in your code, and it's more practical if it's a mid-sized project. Likewise, in real world scenarios, people often ignore error codes returned by functions. if you're going to put the extra mile in favor of robustness, you might as well start with RAII because that will help your application regardless of whether you use exception handling or error code handling.
There is a caveat: you should not throw exceptions across module boundaries. If you do, you should consider a hybrid between error codes (as in returning error codes, not using a global error status like errno) and exceptions.
It is worth noting that if you use operator new in your code without specifying nothrow everywhere, ex:
int* p = new int(123); // can throw std::bad_alloc
int* p = new(std::nothrow) int(123); // returns a null pointer on failure
... then you already need to catch and handle bad_alloc exceptions in your code for it to be robust against out of memory exceptions.
Have a look at this comment by Herb Sutter on try catch for C++ GOTW. And do go through his whole set of articles. He does have a lot to say on when and how to check and save yourself from error conditions and how to handle them in the best ways possible.
Throw an exception. Destructors of variables are always called when an exception is thrown, and if your stack-based variables don't clean up after themselves (if for example you used a raw pointer when you need to delete the result), then you get what you deserve. Use smart pointers, no memory leaks.
But freeing dynamic memory will be an issue when an exception is raised.
Freeing memory (or any other resource for that matter) doesn't suddenly become a non-issue because you don't use exceptions. The techniques that make dealing with these problems while exceptions can be thrown easy, also make it easier when there can be "error conditions".
Exceptions are good for passing control from one context to another.
You let the compiler do the work of unrolling the stack between the contexts then in the new context compensate for the exception (and then hopefully continue).
If your error happens and can be corrected in the same context then error codes are a good method to do error handling and clean up (Don't take this to mean you should not be using RAII you still need that). But for example within a class an error occurs in a function and the calling function can correct for that type of error (then it probably is not an exceptional circumstance so no exceptions) then error code are useful.
You should not use error codes when you have to pass information out of a library or sub system as you are then relying on the developer using the code to actually check and handle the code to make sure it works correctly and more often than not they will ignore error codes.

c++: Operator overloading and error handling

I am currently starting to look into operator overloading in c++ for a simple 2D vertex class where the position should be available with the [] operator. That generally works, but I dont really know how to deal with errors for instance if the operator is out of bounds (in the case of a 2D vertex class which only has x and y values, it is out of bounds if it is bigger than one)
What is the common way to handle errors in cases like that?
Thanks
When you have to throw, you have to throw. There's no other way to diagnose a problem in an overloaded operator unless you can return some sort of magic exploding result value. Define an exception type, throw it on errors, document it.
Error handling is a tricky beast in the best of times. It pretty much boils down to how big a deal the error is, and what if anything is expected to happen with it when it occurs.
There are four basic paths you can follow:
Throw an exception
The sledgehammer of error handling. A great tool, definitely want to use it if you need it, but if you're not careful you'll end up smashing yourself in the foot.
Essentially skips everything between the throw and the catch, leaving nothing but death and destruction in it's wake.
If it's not caught, it will abort your program.
Return a value that indicates failure
Leave it to the programmer to check for success and react accordingly.
Failure value would depend on type. Pointers can return NULL or 0, STL containers return object.end(), else otherwise unused values can be used (such as -1 or "").
Process the condition gracefully
Sometimes, an error isn't really an error, just an inconvenience.
If useful results can still be provided, a mistake can easily be swept under the carpet without hurting anyone.
For example, an out of range error can just return the last variable in an array, without needing to resort to any of that messy exception stuff.
So long as it's predictable and defined, the programmer can make of it what they wish.
Undefined behaviour
Hey, programmers shouldn't be giving you bad input in the first place. Let them suffer.
In general, I would resort to option one only for stuff that's program-breaking, for things that I don't really expect to recover from without concerted effort. Otherwise, using exceptions as a form of flow control is little better than going back to the days of goto.
Option two is probably the most common for non-program-breaking errors, but it's effectiveness really depends on the types of return you're dealing with. It is advantageous since it lets the programmer control the flow locally by detecting failures and recovering themselves. When dealing with overloading operators, it is of limited use, but I figured I'd throw it in for the sake of completeness.
Option three is very circumstance-specific. Many errors can't be handled in such a way, and even the ones that can can lead to unintuitive results. Use with caution, and be sure to document thoroughly. Or, don't document it at all, and pretend it's option four.
Now, as to the specific example provided, that being an out of range error on an overloaded operator[], I would personally go for option four. Not because I particularly enjoy watching other programmers suffer when they deal with my code (I do, incidentally, but that's tangential to the discussion), but because it's expected.
Most cases where a programmer would be using operator[], they expect to handle their own bounds checking and don't rely on the type or class to do anything for them. Even in the STL containers, you can see operator[] (no range checking) in parallel with the otherwise redundant object.at() (which does range checking). Reflecting the expected behaviour with your own overloaded operators tends to make for more intuitive code.
According to the C++ language FAQ, operator[] should not be used for matrices or 2d array implementations; instead use operator().Click here for FAQ #13.10
The big problem is implementing [] for multiple dimensions.
As for errors, you will have to go to the exception route if you don't want to provide any extra parameters to your overloaded operator (another reason to use operator().
I think an assertion might also be in place. Do you foresee that it would ever be anything else than a (simple?) programmer's error to go out of bounds in a 2d vector?
T& operator[](size_t index)
{
assert(index < 2 && "Vector index out of bounds");
return pos[index];
}
If you are going to throw exceptions, I suppose you could also use out_of_range - or a type derived from it.
As others have pointed out, exceptions are the way to go.
But that would seem to be quite an unusual idiom for accessing a point class like that. I would find it much more straightforward for the vertex class to have separate members:
class Vertex {
...
double x;
double y;
};
Then you can operate on them by doing things like vertex1.x - vertex2.x etc, which IMO is more readable than vertex1[0] - vertex2[0]. For an added bonus it avoids your exception problem completely.
You have at least two options other than exceptions for handling indexes out of bounds:
Just trust your input, document that it's undefined behaviour to use an index out of bounds, and rely on your callers to be professionals[*].
Abort if an index is out of bounds, by calling std::terminate(), or abort() directly, or whatever, perhaps after printing an error message.
There's a compromise between the two, which is to use the assert macro. This will do the former in release builds (compiled with NDEBUG), and the latter in debug builds.
Not that exceptions are necessarily a bad idea, but they have their problems. Then again, most of those problems go away if you never catch them.
In this case, the caller has to pass you either 0 or 1. If they sometimes pass you 2, and plan to catch the exception that happens when they do, then there may be no hope for them. Don't spend too much time worrying about it.
Another option would be to accept all inputs, but map them on to one or other of the values. For instance you could bitwise-and the input with 1. This makes your code very simple, with the obvious disadvantage that it obscures other people's bugs.
[*] Not to say that professionals don't make mistakes. They do. They just don't expect you to save them from their mistakes.

How lean do my C++ exception classes really need to be? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
There are lots of places where guidelines for designing exception classes can be found. Almost everywhere I look, there's this list of things exception objects should never do, which impacts the design of those classes.
For instance, the Boost people recommend that the class contain no std::string members, because their constructor could throw, which would cause the run-time to terminate the program immediately.
Now, it seems to me that this is rather theoretical. If std::string's constructor throws, it's either a bug (I passed a null-pointer in) or an out-of-memory condition (correct me if I'm wrong here). Since I'm on a desktop, I just pretend I have an infinite amount of memory, and running out of memory is fatal to my application no matter what.
With that in mind, why shouldn't I embed std::string objects in my exception classes? In fact, why couldn't my exception classes be full-featured, and also take care of logging, stack tracing, etc. I'm aware of the one-responsibility principle, and it seems to me to be a fair trade-off to have the exception class do all that. Surely, if my parser needs to report a syntax error, an full-featured exception would be more helpful than an exception built around a statically allocated character array.
So: lean C++ exception classes - how big a deal is it in the real-world? What are the trade-offs? Are there good discussions on the topic?
You could use the Boost.Exception library to help define your exception hierarchy.
The Boost.Exception library supports the:
transporting of arbitrary data to the
catch site, which is otherwise tricky
due to the no-throw requirements
(15.5.1) for exception types.
The limitations of the framework will provide you with reasonably defined design parameters.
Boost.Exception
See also: Boost.System
As a general case, exception classes should be simple, self-sufficient structures and never allocate memory (like std::string does). The first reason is that allocations or other complex operations may fail or have side effects. The other reason is that exception objects are passed by value and thus are stack-allocated, so they must be as light-weighted as possible. Higher level features should be handled by the client code, not the exception class itself (unless for debugging purpose).
The number one job of an exception, well before any consideration to allowing code to handle the exception, is to be able to report to the user and/or dev exactly what went wrong. An exception class that cannot report OOM but just crashes the program without providing any clue to why it crashed is not worth much. OOM is getting pretty common these days, 32-bit virtual memory is running out of gas.
The trouble with adding a lot of helper methods to an exception class is that it will force you into a class hierarchy that you don't necessarily want or need. Deriving from std::exception is now required so you can do something with std::bad_alloc. You'll run into trouble when you use a library that has exception classes that don't derive from std::exception.
Have a look at the std exceptions they all use std::string internally.
(Or should I say my g++ implementation does, I am sure the standard is silent on the issue)
/** Runtime errors represent problems outside the scope of a program;
* they cannot be easily predicted and can generally only be caught as
* the program executes.
* #brief One of two subclasses of exception.
*/
class runtime_error : public exception
{
string _M_msg;
public:
/** Takes a character string describing the error. */
explicit runtime_error(const string& __arg);
virtual ~runtime_error() throw();
/** Returns a C-style character string describing the general cause of
* the current error (the same string passed to the ctor). */
virtual const char* what() const throw();
};
I usually derive my exceptions from runtime_error (or one of the other standard exceptions).
Since I'm on a desktop, I just pretend I have an infinite amount of memory, and running out of memory is fatal to my application no matter what.
So when your app fatally fails, wouldn't you prefer it to terminate cleanly? Let destructors run, file buffers or logs to be flushed, maybe even display an error message (or even better, a bug reporting screen) to the user?
With that in mind, why shouldn't I embed std::string objects in my exception classes? In fact, why couldn't my exception classes be full-featured, and also take care of logging, stack tracing, etc. I'm aware of the one-responsibility principle, and it seems to me to be a fair trade-off to have the exception class do all that.
Why is that a fair trade-off? Why is it a trade-off at all? A trade-off implies that you make some concessions to the Single-Responsibility Principle , but as far as I can see, you don't do that. You simply say "my exception should do everything". That's hardly a trade-off.
As always with the SRP, the answer should be obvious: What do you gain by making the exception class do everything? Why can't the logger be a separate class? Why does it have to be performed by the exception? Shouldn't it be handled by the exception handler? You may also want to localization, and provide syntax error messages in different languages. So your exception class should, while being constructed, go out and read external resource files, looking for the correct localized strings? Which of course means another potential source of errors (if the string can't be found), adds more complexity to the exception, and requires the exception to know otherwise irrelevant information (which language and locale settings the user uses). And the formatted error message may depend on how it is being shown. Perhaps it should be formatted differently when logged, when shown in a message box, or when printed to stdout. More problems for the exception class to deal with. And more things that can go wrong, more code where errors can occur.
The more your exception tries to do, the more things can go wrong. If it tries to log, then what happens if you run out of disk space? Perhaps you also assume infinite disk space, and just ignore that if and when it happens, you'll be throwing away all the error information?
What if you don't have write permission to the log file?
From experience, I have to say that there are few things more annoying than not getting any information about the error that just occurred, because an error occurred. If your error handling can't handle that errors occur, it isn't really error handling. If you exception class can't handle being created and thrown without causing more exceptions, what is the point?
Normally, the reason for the SRP is that the more complexity you add to a class, the harder it is to ensure correctness, and to understand the code. That still applies to exception classes, but you also get a second concern: The more complexity you add to the exception class, the more opportunities there are for errors to occur. And generally, you don't want errors to occur while throwing an exception. You're already in the middle of handling another error, after all.
However, the rule that "an exception class should not contain a std::string isn't quite the same as "an exception class is not allowed to allocate memory". std::exception does the latter. It stores a C-style string after all. Boost just says not to store objects which may throw exceptions. So if you allocate memory, you just have to be able to handle the case where allocation fails.
Surely, if my parser needs to report a syntax error, an full-featured exception would be more helpful than an exception built around a statically allocated character array.
Says the person who just said he didn't mind the app just terminating with no feedback to the user if an error occurred. ;)
Yes, your exception should contain all the data you need to produce a friendly, readable error message. In the case of a parser, I'd say that would have to be something like:
Input file name (or a handle or pointer which allows us to fetch the filename when needed)
The line number at which the error occurred
Perhaps the position on the line
The type of syntax error that occurred.
Based on this information, you can when handling the error produce a nice friendly, robust error message for the user. You can even localize it if you like. You can localize it when you handle the exception.
Generally, exception classes are for use by the programmer. They should not contain or construct text aimed at the user. That can be complex to create correctly, and should be done when handling the error.
The C++ standard requires that exceptions have no-throw copy costructor. If you have a std::string member, you don't have a no-throw copy constructor. If the system fails to copy your exception, it'll terminate your program.
It is also a good idea to use virtual inheritance in designing your exception type hierarchy, as explained in http://www.boost.org/doc/libs/release/libs/exception/doc/using_virtual_inheritance_in_exception_types.html.
However, there is no requirement that exception objects be simple or not allocate memory. In fact, exception objects themselves are typically allocated on the heap, so the system may run out of memory in an attempt to throw an exception.
I think refusing to use std::string in exception classes is unnecessary purism. Yes, it can throw. So what? If your implementation of std::string throws for reasons other than running out of memory just because you're constructing a message "Unable to parse file Foo", then there is something wrong with the implementation, not with your code.
As for running out of memory, you have this problem even when you construct an exception which takes no string arguments. Adding 20 bytes of helpful error message is unlikely to make or break things. In a desktop app, most OOM errors happen when you try to allocate 20 GB of memory by mistake, not because you've been happily running at 99.9999% capacity and something tipped you over the top.
... running out of memory is fatal to my application no matter what.
Unfortunately this is exactly what most people say because they don't want to deal with the complexity that arises otherwise. On the other hand, if you do follow the requirements set by the standard, you get much more robust software that can recover even in low-memory conditions.
Leaving mars rovers aside, think of such a simple case like writing a text processor. You want to implement a copy/paste feature. The user selects some text and hits Ctrl+C. What outcome you prefer: a crash or a message "Not enough memory"? (If there was no enough memory to show the message box just nothing happens.) The second scenario is no doubt much more user friendly, she can just close some other app and continue working on her document.
In fact it's not so hard to guarantee the no-throw copy constructor. You should just store a shared pointer inside your exception that points to the dynamically allocated memory:
class my_exception : virtual public std::exception {
public:
// public interface...
private:
shared_ptr<internal> representation;
};
Assuming that exceptions are for exceptional situations, the atomic count overhead is negligible. In fact this is what Boost.Exception does.
With that said, I recommend jalf's answer as well.