Document Number |
P1197R0 |
Date |
2018-09-27 |
Project |
Programming Language C++ |
Audience |
Library Evolution Working Group |
Summary |
This paper proposes a non-allocating overload of |
Rationale
The facilities in <system_error>
are suitable for reporting errors in resource-constrained environments,
but the function message
, specified to return an std::string
, mandates allocation, which may be prohibited.
Therefore, an overload of message
is proposed that returns the message into a caller-supplied buffer.
The function’s interface is modeled after the Glibc-specific strerror_r
function, as it allows literals to
be directly returned without a string copy or truncation.
The default error_category
implementation of the new overload calls the existing message(ev)
and returns
the string into the supplied buffer, in order to retain backward compatibility.
Implementability
The proposed changes have been implemented in Boost.System and currently reside on its develop branch. They are expected to ship in Boost 1.69.
Proposed Changes
-
namespace std { class error_category { public: constexpr error_category() noexcept; virtual ~error_category(); error_category& operator=(const error_category&) = delete; virtual const char* name() const noexcept = 0; virtual error_condition default_error_condition(int ev) const noexcept; virtual bool equivalent(int code, const error_condition& condition) const noexcept; virtual bool equivalent(const error_code& code, int condition) const noexcept; virtual string message(int ev) const = 0; virtual const char* message(int ev, char* buffer, size_t len) const noexcept; bool operator==(const error_category& rhs) const noexcept; bool operator!=(const error_category& rhs) const noexcept; bool operator< (const error_category& rhs) const noexcept; }; const error_category& generic_category() noexcept; const error_category& system_category() noexcept; }
-
virtual const char* message(int ev, char* buffer, size_t len) const noexcept;
Effects: -
If
len
is 0, returnsbuffer
; -
Otherwise, if
message(ev)
doesn’t throw, copies the string returned bymessage(ev)
intobuffer
, truncating it tolen-1
characters and adding a null terminator, and returnsbuffer
; -
Otherwise, either returns a pointer to an implementation-defined string literal, or copies an implementation-defined message into
buffer
, truncating it tolen-1
characters and adding a null terminator, and returnsbuffer
.
-
-
virtual const char* message(int ev, char* buffer, size_t len) const noexcept;
Effects: -
If a character literal that describes
ev
is available, returns a pointer to it; -
Otherwise, if
len
is 0, returnsbuffer
; -
Otherwise, copies a message describing
ev
intobuffer
, truncating it tolen-1
characters and adding a null terminator, and returnsbuffer
.[Note:
message(ev, nullptr, 0)
is allowed. --end note][Note: If the function returns a pointer distinct from
buffer
, the caller may assume that it points to a character literal. --end note][Example:
const char* my_category::message(int ev, char* buffer, size_t len) const noexcept { switch(ev) { case 0: return "no error"; case 1: return "voltage out of range"; case 2: return "impedance mismatch"; case 31: case 32: case 33: std::snprintf(buffer, len, "component %d failure", ev-30); return buffer; default: std::snprintf(buffer, len, "unknown error %d", ev); return buffer; } }
--end example]
-
-
const char* message(char* buffer, size_t len) const noexcept;
Returns: category().message(value(), buffer, len)
.
-
const char* message(char* buffer, size_t len) const noexcept;
Returns: category().message(value(), buffer, len)
.
ABI Implications
The proposed addition of a new virtual function to error_category
unfortunately constitutes an ABI break,
although its impact is relatively limited, as it only affects new code calling the new message
overload
on error_code
objects from user-defined categories returned by old code.
Adopting the versioning mechanism proposed in P1196R0, if deemed workable, could allow even the above scenario.
-- end