I'm writing a program where I have created a std::vector of POD structs. One of the members of the struct is a unique identifier.
In order to be able to use std::binary_search I have to implement operator< for the struct. Following the guidelines here, I'm writing the full set of overloads for ==, !=, <, >, >= and <=.
This presents one issue I wasn't sure how to handle. The vector will be ordered by the unique ID I assign each struct. Two structs are the same if they have the same identifier. However, it occurs to me that a situation could crop up if two structs have the same identifier but different data in the other members.
This should never happen. Would it be appropriate to have the comparison operator check the rest of the fields then and throw an exception if they're different but the ID is the same? What sort of exception would be most appropriate?
This is merely an expansion on SCombinator's answer.
The fact that you said "This should never happen." means you want to use an assert, not an exception (or a combination of the two). An exception would hide the error - well, not hide, but you'll be able to catch it and continue. It is better suited for exceptional situations which you didn't really plan for - for example you're attempting to open a file that doesn't exist. It's not really part of the logic that the file is missing, it's your little brother accidentally deleting your file, or an aggressive anti-virus that thought it was a virus, or whatever - it's just an exceptional situation.
If members with the same ID but otherwise different is something that should never happen, that's basically an assertion. It's part of the logic - part of the requirements if you will. Throwing an exception simply points this out, but there's not really a way you can recover from it. By the time you realize something is wrong, it's already 2 late. You have two objects with the same id, yet different, you don't know which one is correct, you don't know why the incorrect one exists, and so on. You probably don't even want to recover from it. The application is already in a erroneous state - the two contradicting objects already exist. Your application is in an un-recovarable state - if you continue with it, you'll probably get wrong results or worse.
If it's not a critical assertion, you can also throw an exception afterwards, and provide a clean way to close the application, but that's just a beautification.
In general, I follow a simple rule - If it's something that can happen under extraordinary circumstances, I use exceptions. If it's something that should never happen, and if it does, means something is seriously wrong with the logic in the code, I use an assert (and possibly a force crash).
If such a thing is a logical error, you should probably use an assert.
Well, you have to ask yourself a few questions:
1) Is this likely to happen during testing (ie signaling a bug) but will never happen during normal execution? If the answer is yes, use an assert.
2) Is this going to happen during normal runtime, and if so, can the program recover and continue execution? If the answer is yes, throw an error, catch and handle it.
3) Is this going to happen during normal runtime and is it unrecoverable? If yes, either call abort or something like that (exit, terminate) or throw an exception which you're not going to handle.
Bad data should be rejected when the data is created. It's not the job of comparison operators to weed out mistakes; that should be done before the program does any serious data manipulation. So the answer to the question is no, operator== and operator!= should not throw exceptions on bad data; they should be written with the assumption that the data that's being passed to them is valid.
You could just use a map which is implemented with a binary search tree, although you'd be duplicating an id. Then again, you wouldn't even need to store the id in the struct, since they are supposed to be unique.
// Example POD struct.
struct MyStruct
{
int id; // Redundant.
char a;
}
std::map<int, MyStruct> myMap;
MyStruct m; m.id = 1;
myMap[m.id] = m;
// Or simply..
myMap[1] = m;
Related
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!
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.
I have a class containing union as a field. The union is of pointers to two different classes. As a second field my class contains a flag informing which type is currently stored.
class Item {
std::string *title;
bool who_am_I;
union { Submenu *smenu; Function *call; } content;
public:
bool am_I_a_submenu();
bool am_I_a_function();
Submenu *give_me_submenu();
Function *give_me_function();
/*(...)*/
};
Now, before each usage of my "give_me" methods I urge user to check the type through the appropriate method accessing the flag, i.e. the "am_I" methods. Nevertheless I would like my library to throw appropriate exception if the user would happen to forget about it. Can I do that without checking the flag inside the "give_me" method? I ask because it would mean that in normal usage the flag is unnecessarily checked twice.
I was wondering if, which and when does c++ throw some in build exception once the conflict of types will appear causing program malfunctioning. Or maybe should I handle this case otherwise, still preferably without double checking the flag.
OK, first of all... why do you care if the flag is checked twice? Is that really a serious performance bottleneck in your product that profiling has shown must be optimized? I very much doubt it.
But even if it is a performance bottleneck, what's more important? A properly functioning application that doesn't crash seems to me to be an acceptable tradeoff for a super-tiny amount of extra overhead.
But you should probably just redesign your interface(s) so that the user always knows what he has and can't make mistakes like this.
There is no way to check what's stored inside union. If you use union, it's up to you to make sure you are always accessing the right element. Reading the wrong one is undefined behavior and will not throw exception.
I don't know what are you doing, but I would recommend you not to use union at all. It's an old fashioned way to save some memory and not worth the bugs it is likely to introduce. In your case, it does not save memory at all (preceeding boolean takes as much memory as a pointer would, because of memory alignment).
By using a union you are telling the compiler that the two types are compatible. Normally converting from the two would cause a compile time issue, since there is no user-specified, nor default conversion, however since you defined it as a union there is a default conversion to both types.
I would postulate that an extra call to check a boolean is probably not too expensive in this case.
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. ;)
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.