开发者

C++ - Where to throw exception?

开发者 https://www.devze.com 2023-01-02 08:56 出处:网络
I have some kind of an ideological question, so: Suppose I have some templated function template <typename Stream>

I have some kind of an ideological question, so:

Suppose I have some templated function

template <typename Stream>
void Foo(Stream& stream, Object& object) { ... }

which does something with this object and the stream (for example, serializes that object to the stream or something like that).

Let's say I also add some plain wrappers like (and let's say the number of these wrappers equals 2 or 3):

void FooToFile(const std::string& filename, Object& object)
{
   std::ifstream stream(filename.c_str());
   Foo(stream, object);
}

So, my question is:

Where in this case (ideologically) should I throw the exception if my stream is bad? Should I do this in each wrapper or just move that check to my Foo, so that it's body would look like

if (!foo.good()) throw (something);
// Perform ordinary actions

I understand that this may be not the most important part of coding and开发者_开发知识库 these solutions are actually equal, but I just wan't to know "the proper" way to implement this.

Thank you.


In this case it's better to throw it in the lower-level Foo function so that you don't have to copy the validation and exception throwing code in all of your wrappers. In general using exceptions correctly can make your code a lot cleaner by removing a lot of data validation checking that you might otherwise do redundantly at multiple levels in the call stack.


I would prefer not to delay notifying an error. If you know after you have created the stream, that it is no good, why call a method that works on it? I know that to reduce code-redundancy you plan to move it further down. But the downside of that approach is a less-specific error message. So this depends to some extent on the source-code context. If you could get away with a generic error message at the lower-function level you can add the code there, this will surely ease maintanence of the code especially when there are new developers on the team. If you need a specific error message better handle it at the point of failure itself.

To avoid code redundancy call a common function that makes this exception/error for you. Do not copy/paste the code in every wrapper.


The sooner you catch the exceptiont the better. The more specific the exception is - the better. Don't be scared of including most of your code into a try catch blocks, apart fromt he declaration.

For example:

int count = 0;
bool isTrue = false;
MyCustomerObject someObject = null;

try
{
   // Initialise count, isTrue, someObject. Process.
}
catch(SpecificException e)
{
// Handle and throw up the stack. You don't want to lose the exception.
}


I like to use helper functions for this:

struct StreamException : std::runtime_error
{ 
    StreamException(const std::string& s) : std::runtime_error(s) { }
    virtual ~StreamException() throw() { }
};

void EnsureStreamIsGood(const std::ios& s)
{
    if (!s.good()) { throw StreamException(); }
}

void EnsureStreamNotFail(const std::ios& s)
{
    if (s.fail()) { throw StreamException(); }
}

I test them immediately before and after performing stream operations if I don't expect a failure.


Traditionally in C++, stream operations don't throw exceptions. This is partly for historic reasons, and partly because streaming failures are expected errors. The way C++ standard stream classes deal with this is to set a flag on a stream to indicate an error has occurred, which user code can check. Not using exceptions makes resumption (which is often required for streaming ops) easier than if exceptions were thrown.

0

精彩评论

暂无评论...
验证码 换一张
取 消