Document number: N2769 = 08-0279
Date: 2008-09-17
Project:
Programming Language C++, Library Working Group
Reply-to:
Beman Dawes <bdawes at acm.org>
Introduction
Revision History
Motivation
Approach
C++0x or TR2?
Implementation experience
Acknowledgements
Proposed wording
This paper proposes adding detailed error reporting, based on C++ standard library System error support (19.4), to the C++ standard library's Input/output library (27).
This proposal is a major revision of
N2655. At the request of the LWG, the proposed change is now limited to
changing the base class of
ios_base::failure
to system_error
, and supplying the
boilerplate to support that change.
The specification of std::system_error
as a base class of
std::basic_ios::failure
was originally proposed in
N2503, Indicating iostream failures with system_error
.
Lack of detailed error reporting has long been a concern about the C++ I/O Streams library. For example, The C++ Standard Library by Nicolai Josuttis, complained in 1999:
Unfortunately, the standard does not require that the exception object includes any information about the erroneous stream or the kind of error.
The problem is particularly acute for failures to open a file. Such failures are extremely common and there are numerous possible reasons for failure, such as the file not being found, the permissions being wrong, and so forth. Diagnosing these failures without knowing the exact reason for failure is difficult, irritating, and time wasting.
The only known case where the proposal might break existing code is code that
depends on ios_base::failure
being derived directly from
exception
. Library
clause 17.4.4.7 has always granted implementers permission to derive classes
from classes other than the specified base, so such code is already suspect.
The proposal does break ABI compatibility in that the exception class derivation changes.
Because of the ABI breakage, the LWG prefers to see this change in C++0x.
A C++03 proof-of-concept prototype of the proposal has been implemented by modifying the Apache C++ Standard Library. No difficulties were encountered and coding was straightforward. Virtually all changes were on paths through the code that are only executed when a failure has already been detected.
Alisdair Meredith initiated the original N2503 proposal and helped with the preparation of the current proposal.
To 27.4 Iostreams base classes [iostreams.base], Header <ios>
synopsis, add:
enum class ioerrc { stream=1 }; concept_map ErrorCodeEnum<ioerrc> {}; error_code make_error_code(ioerrc e); error_condition make_error_condition(ioerrc e); storage-class-specifier const error_category& iostream_category;These additions are the boilerplate required to create a new error category. See 19.4 of the WP.
In a new sub-section, Error category object, add:
storage-class-specifier const error_category& iostream_category;The implementation shall initialize iostream_category. Its storage-class-specifier is permitted to be static or extern. It is unspecified if initialization is static or dynamic (3.6.2 [basic.start.init]). If initialization is dynamic, it shall occur before completion of the dynamic initialization of the first translation unit dynamically initialized that includes header <system_error>.
The exact form and wording for describing error_category initialization is the topic of issue 890. The above paragraph needs to be kept in sync with the final disposition of 890.
The object’s
default_error_condition
andequivalent
virtual functions shall behave as specified for the classerror_category
. The object’sname
virtual function shall return a pointer to the string"iostream"
.
At a location to be determined, add:
error_code make_error_code(ioerrc e);
Returns:
error_code(static_cast<int>(e), io_category)
.
error_condition make_error_condition(ioerrc e);
Returns:
error_condition(static_cast<int>(e), io_category)
.
Change 27.4.2.1.1 Class ios_base::failure [ios::failure] as indicated:
namespace std { class ios_base::failure : public
exceptionsystem_error { public: explicit failure(const string& msg, const error_code& ec = ioerrc::stream); explicit failure(const char* msg, const error_code& ec = ioerrc::stream); virtual const char* what() const throw(); }; }The class
failure
defines 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.When throwing
ios_base::failure
exceptions, implementations are encouraged to provide values of ec that identify the specific reason for the failure. [Note - Errors arising from the operating system would typically be reported assystem_category
errors with an error value of the error number reported by the operating system. Errors arising from within the stream library would typically be reported aserror_code(
ioerrc::stream, iostream_category)
-- end note].The above wording provides only normative encouragement for implementers to do the right thing, and thus relies on market forces and the good intensions of implementers to produce results useful to users. Anything stronger (such as changing "are encouraged to" to "shall") would require much additional specification and is beyond the scope of what the LWG can realistically tackle for C++0x.
explicit failure(const string& msg, const error_code& ec = ioerrc::stream);
Effects: Constructs an object of class
failure
.Postcondition:
code() == ec
andstrcmp(what(), msg.c_str()) == 0
explicit failure(const char* msg, const error_code& ec = ioerrc::stream);
Effects: Constructs an object of class
failure
.Postcondition:
code() == ec
andstrcmp(what(), msg ) == 0