• 11
• 9
• 11
• 9
• 11

# throw multiple exception types

This topic is 3549 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I want to specify what exceptions Get may throw with the 'throw' modifier. It can explicitly throw EngineVariableNotFound, and may implicitly throw boost::bad_lexical_cast. Is there a way to specify both of these? Would it be better design to put a try block around the lexical_cast, and rethrow EngineVariableBadLexicalCast? Seems like it adds confusion instead of reducing it. My goal is most maintainable code. I realize the boost::format may also throw, is the best way to deal with that to tell it not to throw? Also, what's the cleanest way to return the error code - i think the returned char* is a dangling pointer, though I don't think I'm allowed to change the signature of what()
class Var {
class EngineVariableException : public std::exception
{};

class EngineVariableNotFound : public EngineVariableException
{
std::string varStr;
public:

virtual const char* what() const throw()
{
% varStr).str().c_str();
}
};
//class EngineVariableBadLexicalCast : public EngineVariableException {};

template <typename T> static T Get(std::string varStr) //throw (EngineVariableException)
{
C4::Variable *var = TheEngine->GetVariable(varStr.c_str());
if (!var) throw EngineVariableNotFound(varStr);
return boost::lexical_cast<T>(var->GetValue());
}
}



##### Share on other sites
First of all, try to throw as few types of exception as possible. Any exceptions that function A throws should have meaning to any function which calls Function A, and potentially be recoverable. That is, if function A is PrintDocument, it makes sense to be able to throw a NoPaperException, because someone who's printing something should understand that paper is potentially involved and may be able to do something about it. However, PrintDocument should NOT throw a BSplineArcLengthParameterizationException, even if one happened internally while trying to render a font, because the function that's trying to print a document shouldn't need to know what a B-spline is, and wouldn't know how to proceed even if it did. In your case, bad_lexical_cast is almost certainly something that should be caught internally and rethrown as something more meaningful to the user. The user of the class should not need to know that there's lexical casting going on.

In C++, exception specifications are rarely used, with the possible exception of empty exception specifications. They're a great idea on the high level (and are certainly well-leveraged in Java) but the C++ implementation does more harm than good. More info here.

##### Share on other sites
Catching just to translate is occasionally bad, and catching just to squelch is often bad. Catching just to rethrow, unmodified, is almost always bad. The exceptions (har har) to this rule often come up across API boundaries. In general, as Sneftel says, throw as little as possible -- but balance that with making sure you throw something that the client can reasonably expect and handle, and making sure you only catch to do something useful.

EDIT: To make sure I get my point across, I'm essentially agreeing with Sneftel in this case -- letting the format exception out of this method probably isn't useful except as a way to indicate that your code broke. There's nothing the caller could ever do to recover from it, other than maybe retry the operation. There are cases, however, where letting an internal except propagate out is good because the client could handle and recover from it, and in that it's probably foolish to translate the exception since the original is just as useful.

C++ supports exception specification:
T foo(Q bar) throw (exceptionA, exceptionB);

You can simply list your desired exceptions types in the throw() block, even if you don't throw them explicitly (as is the case with the Boost format exception). However, be aware that these specifications are weakly supported among C++ compilers (including Visual Studio, which last I checked basically treats all exception specifications except the empty, no-throw specification as "this will throw anything") and that they don't necessarily act the way you'd expect.

[Edited by - jpetrie on August 4, 2008 10:32:02 AM]

##### Share on other sites
How do I deal with the dangling string pointer? Changing to virtual std::string what() doesn't work. Am I forced to just allocate a buffer and put a shared_ptr around it? I can't modify the return signature to be shared_ptr...

error C2555: 'Var::EngineVariableNotFound::what': overriding virtual function return type differs and is not covariant from 'std::exception::what'