system_error
constructor postcondition overly strictSection: 19.5.8.2 [syserr.syserr.members] Status: C++11 Submitter: Howard Hinnant Opened: 2009-04-25 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [syserr.syserr.members].
View all issues with C++11 status.
Discussion:
19.5.8.2 [syserr.syserr.members] says:
system_error(error_code ec, const string& what_arg);Effects: Constructs an object of class
system_error
.Postconditions:
code() == ec
andstrcmp(runtime_error::what(), what_arg.c_str()) == 0
.
However the intent is for:
std::system_error se(std::errc::not_a_directory, "In FooBar"); ... se.what(); // returns something along the lines of: // "In FooBar: Not a directory"
The way the constructor postconditions are set up now, to achieve both
conformance, and the desired intent in the what()
string, the
system_error
constructor must store "In FooBar" in the base class,
and then form the desired output each time what()
is called. Or
alternatively, store "In FooBar" in the base class, and store the desired
what()
string in the derived system_error
, and override
what()
to return the string in the derived part.
Both of the above implementations seem suboptimal to me. In one I'm computing
a new string every time what()
is called. And since what()
can't propagate exceptions, the client may get a different string on different
calls.
The second solution requires storing two strings instead of one.
What I would like to be able to do is form the desired what()
string
once in the system_error
constructor, and store that in the
base class. Now I'm:
what()
only once.what()
definition is sufficient and nothrow.This is smaller code, smaller data, and faster.
ios_base::failure
has the same issue.
[
Comments about this change received favorable comments from the system_error
designers.
]
[ Batavia (2009-05): ]
We agree with the proposed resolution.
Move to Tentatively Ready.
Proposed resolution:
In 19.5.8.2 [syserr.syserr.members], change the following constructor postconditions:
system_error(error_code ec, const string& what_arg);-2- Postconditions:
code() == ec
and.
strcmp(runtime_error::what(), what_arg.c_str()) == 0string(what()).find(what_arg) != string::npossystem_error(error_code ec, const char* what_arg);-4- Postconditions:
code() == ec
and.
strcmp(runtime_error::what(), what_arg) == 0string(what()).find(what_arg) != string::npossystem_error(error_code ec);-6- Postconditions:
code() == ec
and.strcmp(runtime_error::what(), ""
system_error(int ev, const error_category& ecat, const string& what_arg);-8- Postconditions:
code() == error_code(ev, ecat)
and.
strcmp(runtime_error::what(), what_arg.c_str()) == 0string(what()).find(what_arg) != string::npossystem_error(int ev, const error_category& ecat, const char* what_arg);-10- Postconditions:
code() == error_code(ev, ecat)
and.
strcmp(runtime_error::what(), what_arg) == 0string(what()).find(what_arg) != string::npossystem_error(int ev, const error_category& ecat);-12- Postconditions:
code() == error_code(ev, ecat)
and.strcmp(runtime_error::what(), "") == 0
In 19.5.8.2 [syserr.syserr.members], change the description of what()
:
const char *what() const throw();-14- Returns: An NTBS incorporating
the arguments supplied in the constructor.runtime_error::what()
andcode().message()
[Note:
One possible implementation would be:The return NTBS might take the form:what_arg + ": " + code().message()
if (msg.empty()) { try { string tmp = runtime_error::what(); if (code()) { if (!tmp.empty()) tmp += ": "; tmp += code().message(); } swap(msg, tmp); } catch(...) { return runtime_error::what(); } return msg.c_str();— end note]
In [ios::failure], change the synopsis:
namespace std { class ios_base::failure : public system_error { public: explicit failure(const string& msg, const error_code& ec = io_errc::stream); explicit failure(const char* msg, const error_code& ec = io_errc::stream);virtual const char* what() const throw();}; }
In [ios::failure], change the description of the constructors:
explicit failure(const string& msg, , const error_code& ec = io_errc::stream);-3- Effects: Constructs an object of class
failure
by constructing the base class withmsg
andec
.
-4- Postcondition:code() == ec
andstrcmp(what(), msg.c_str()) == 0
explicit failure(const char* msg, const error_code& ec = io_errc::stream);-5- Effects: Constructs an object of class
failure
by constructing the base class withmsg
andec
.
-6- Postcondition:code() == ec and strcmp(what(), msg) == 0
In [ios::failure], remove what
(the base class definition
need not be repeated here).
const char* what() const;
-7- Returns: The messagemsg
with which the exception was created.