10

Looking at some old code we have lots of things like the following:

// This is dumb
string do_something(int in)
{
    stringstream out;
    try
    {
        out << std::fixed << in;
    }
    catch(std::exception &e)
    {
        out << e.what();
    }

    return out.str();
}

// Can't we just do this? Can this ever fail?
string do_something_better(int in)
{
    stringstream out;
    out << std::fixed << in;
    return out.str();
}

When a stringstream reads a primitive can it ever throw an exception? What about when reading a string?

LeviX
  • 3,096
  • 3
  • 28
  • 41
  • 12
    That code is insane. You're catching an error raised by the stream, and then using the **same stream** to try to communicate that error. Worse, you're littering your low-level code with completely meaningless exception handling which does nothing to *recover* from the error, leaving the stream in a broken state. You should be catching these errors at a level where you can *do* something about them, even if it's just alerting the user and aborting the program. This is a complete abuse of exception handling. – user229044 Jul 07 '12 at 21:14
  • It can throw exceptions, but only if you have enabled them by calling `out.exceptions(selected_exceptions)`. A default constructed stream doesn't throw exceptions (except `bad_alloc`, which you can hardly handle here). – Bo Persson Jul 07 '12 at 21:21
  • You can totally handle `bad_alloc`. Just free a bunch of memory. – Mooing Duck Jul 07 '12 at 21:32
  • @BoPersson So the try/catch block is useless pretty much – LeviX Jul 07 '12 at 21:44
  • You can possibly handle `bad_alloc`, but not here. Let it propagate! Having a catch statement *here* is pretty useless. – Bo Persson Jul 07 '12 at 21:48
  • Good reasoning meager. Your initial analysis is spot on. – LeviX Jul 09 '12 at 17:37
  • @meagar, while you are *kind of* correct, it is worth noting that after an exception, it is guaranteed that an STL stream is in a valid state. – bochko May 13 '18 at 21:49

2 Answers2

12

Summarizing a few answers

By default, streams don't throw exceptions. They can if they are enabled.

stringstream out;
out.exceptions(std::ios::failbit);   // throw exception if failbit gets set

According to the Apache C++ Standard Library User's Guide

The flag std::ios_base::badbit indicates problems with the underlying stream buffer. These problems could be:

Memory shortage. There is no memory available to create the buffer, or the buffer has size 0 for other reasons (such as being provided from outside the stream), or the stream cannot allocate memory for its own internal data, as with std::ios_base::iword() and std::ios_base::pword().

The underlying stream buffer throws an exception. The stream buffer might lose its integrity, as in memory shortage, or code conversion failure, or an unrecoverable read error from the external device. The stream buffer can indicate this loss of integrity by throwing an exception, which is caught by the stream and results in setting the badbit in the stream's state.

Generally, you should keep in mind that badbit indicates an error situation that is likely to be unrecoverable, whereas failbit indicates a situation that might allow you to retry the failed operation.

So it seems like the safest way to do this would be

string do_something(int in)
{
    stringstream out; // This could throw a bad_alloc
    out << std::fixed << in; // This could set bad or fail bits

    if(out.good())
    {
        return out.str();
    }
    else
    {
        return "";
    }
}

This is overkill though because according to Handling bad_alloc if creating the stream fails, there are bigger problems to worry about, and the program is probably going to exit. So assuming it gets past creating the stream, it's possible but extremely unlikely that the badbit gets set. (Stream gets allocated with memory < sizeof(int)).

It's also unlikely that the failbit gets set (not sure of a use case for reading off the stack other than a corrupt stack). So the following code is sufficient, as recovering from a stream error at this point is unlikley.

string do_something(int in)
{
    stringstream out;
    out << std::fixed << in;
    return out.str();
}
Community
  • 1
  • 1
LeviX
  • 3,096
  • 3
  • 28
  • 41
2

All streams, including istringstreams, can throw exceptions (controllable with ios::exceptions) on reading, eg. when they run out of input. Plus they can throw when running out of memory (eg. when constructing the string currently read).

Your code example, however, performs writing(?) AFAIK writing and int should not produce any exceptions, apart from the obvious out of memory errors (which your code doesn't handle very well).

jpalecek
  • 47,058
  • 7
  • 102
  • 144