public member functions of
std::basic_streambuf which perform i/o —
pubsync(), etc. — are implemented using the
protected virtual interface of
sync(), etc. Most of these
protected virtual functions are allowed to signal failure either by throwing an exception or by returning an error indicator (often
traits_type::eof()). All exceptions thrown are propogated by the
public member functions, so users of raw stream buffers must in principle be prepared to handle exceptions. However, the stream buffers which ship with most standard library implementations do not throw exceptions.
Standard streams, by contrast, throw no exceptions by default: users must set the exception mask to request that exceptional conditions be reported using exceptions. If
ios_base::badbit is set in a stream's exception mask, all exceptions thrown by the underlying stream buffer will be caught and rethrown.
With streams, therefore, the user has a choice whether to enable exceptions; with stream buffers, the implementor has a choice, but the user has none.
The fundamental stream buffer template in the Boost Iostreams library,
stream_buffer, implements the
protected virtual memeber functions of
std::basic_streambuf by delegating to the i/o functions
get, etc., which in turn delegate to member functions of Filters and Devices. These member functions throw exceptions to report errors. The exceptions are propagated by the
protected virtual members of
stream_buffer and by the public members of
It is recommended that all exceptions thrown by user-defined Filters and Devices
An alternative formulation would have been to require Filter and Device member functions with return type
std::streamsize to return
-1 to indicate errors, and to modify the specification of functions returning
void so that they return a
bool indicating success. The decision to rely on exceptions to report errors was made to allow implementors a means to convey aditional information about the cause of errors, and to free them from having to remember which return values are designated as error indicators.
A third possibility would have been to follow the example of
std::basic_streambuf and allow member functions of Filters and Devices to signal errors either by throwing exceptions or by returning designated error indicators. This was rejected because it would have complicated the specifications of the various Filter and Device concepts and made the internals of
stream_buffer more difficult to understand and maintain.
close, if appropriate.
streamcan be closed and reopened to perform additional i/o with a new instance of the underlying Filter or Device type.
filtering_stream's chain of Filters and Devices is in a consistent state. If the current Device is removed from the chain and a new one added the user may perform i/o as if the the stream or stream buffer were newly constructed.
Conditions 2. and 3. rely on the specification of the Filter and Device concepts. Note that there is no guarantee that a stream's or stream buffer's character sequences are in a consistent state, i.e., that data has not been corrupted, and no way in general to determine the state of these sequences after an exception.
These conditions amount to what is known as the basic guarantee of exception safety (see [Abrahams1].)
Thanks to Angelika Langer and John Torjo for discussion of exceptions.
The C++ standard describes
std::ios_base::failure as "the base class for the types of all objects thrown as exceptions, by functions in the Iostreams library, to report errors detected during stream buffer operations." ([ISO], section 184.108.40.206.1.) There is a difference of opinion among commentators whether this means that all exceptions thrown by stream buffer member functions must be of type
A leading text on C++ iostreams interprets the language in the standard to mean that exceptions "may be of any type" but that "if the exception is rasied due to an error situation discovered by any of the IOStreams operations, it is of the type
failure" ([Langer], p. 36, emphasis added). As an example, the authors state that a
std::bad_alloc generated during buffer allocation need not be caught and rethrown as a
Another leading text, however, takes the view that all exceptions must derive
failure. ([Josuttis1], p. 602.)
The Iostreams library takes a neutral position on this matter: all exceptions thrown
internally by the library are of type
failure or a derived class, but exceptions
thrown by user-defined types are propogated as-is.
As Herb Sutter writes, "it is always poor design to allow an operation to report the same error in two different ways....It complicates the interface and the semantics. And it makes the caller's life harder because the caller must be able to handle both flavors of error reporting." ([Sutter], p. 130.)
Revised 02 Feb 2008
© Copyright 2008 CodeRage, LLC
© Copyright 2004-2007 Jonathan Turkanis
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)