Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

OO design: Is "errno" Exception?

3 views
Skip to first unread message

Hansoo

unread,
May 7, 2003, 5:57:16 AM5/7/03
to
I am designing several system wrapper class, and I have encountered a
question to treat "errno" in UNIX system calls?

For example, send()/recv() call to the socket may return negative
value when there is a problem and the reason is specified in errno. If
follow the idiom suggested by Bjarne Stroustrup that Exception is used
for error handling (not for program control), my question becomes that
errno is error condition (even though the name sounds simiar).

If I take socket as reliable (even disconeection is always done
through mutual agreement), it is definately an error. If I think
socket disconnection is expected behavior (rather than disastrous
condition), this is not an error. Am I appraching this in a right way?
Any thought?

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Frank A. Uepping

unread,
May 9, 2003, 5:56:51 AM5/9/03
to
Hansoo wrote:

> I am designing several system wrapper class, and I have encountered a
> question to treat "errno" in UNIX system calls?
>
> For example, send()/recv() call to the socket may return negative
> value when there is a problem and the reason is specified in errno. If
> follow the idiom suggested by Bjarne Stroustrup that Exception is used
> for error handling (not for program control), my question becomes that
> errno is error condition (even though the name sounds simiar).

If this is an error depends on the viewpoint.
From the OS side yes -- the requested operation couldn't succeed.
From the user side yes and no depending on the situation.
But you can regard it as an exception -- exceptions need not to be errors!

Raoul Gough

unread,
May 9, 2003, 10:51:41 PM5/9/03
to
"Hansoo" <ki...@yahoo.com> wrote in message
news:8789b62d.03050...@posting.google.com...

> I am designing several system wrapper class, and I have encountered
a
> question to treat "errno" in UNIX system calls?
>
> For example, send()/recv() call to the socket may return negative
> value when there is a problem and the reason is specified in errno.
If
> follow the idiom suggested by Bjarne Stroustrup that Exception is
used
> for error handling (not for program control), my question becomes
that
> errno is error condition (even though the name sounds simiar).
>
> If I take socket as reliable (even disconeection is always done
> through mutual agreement), it is definately an error. If I think
> socket disconnection is expected behavior (rather than disastrous
> condition), this is not an error. Am I appraching this in a right
way?
> Any thought?

You probably are approaching it the right way, because it seems like
you're not sure! Some cases are easy, of course - for instance, if you
have enabled asynchronous I/O on the socket, then EAGAIN or
EWOULDBLOCK are obviously expected conditions. Whether ECONNRESET (or
EPIPE?) is an error probably depends on the application layer
protocol, although I think if the client code is still attempting to
read or write after the other end closes then there is probably
something wrong, like the other end has crashed. Or maybe you use a
socket close as part of the application level protocol - in which case
you might want to allow dynamic configuration of the handling,
depending on the application state.

The standard I/O streams do not produce exceptions by default, but you
can enable them if you want (I've never tried this, BTW). Maybe you
could do something similar...

--
Raoul Gough
see http://home.clara.net/raoulgough/ for my work availability

Early Ehlinger

unread,
May 21, 2003, 8:04:15 PM5/21/03
to
"Raoul Gough" <Raoul...@yahoo.co.uk> wrote:
> The standard I/O streams do not produce exceptions by default, but you
> can enable them if you want (I've never tried this, BTW). Maybe you
> could do something similar...

This is IMHO a dangerous road to travel down. I truly wish the Standard did
*not* have this capability and instead ALWAYS used exceptions to indicate
failure.

An error is an error is an error.

If your program doesn't handle it (even if handling it means explicitly
ignoring it with catch(<condition>){} ), you've got a bug. You might argue
to me that implicitly ignoring it is perfectly suitable. I beg to differ on
the grounds that implicitly ignoring an error condition is too close to
accidentally ignoring the error condition and somebody maintaining your code
is not likely to know the difference later. I will grant that exceptions
*can* cause additional overhead, but they certainly do not *have to* and can
even reduce overhead by minimizing the need for explicit error propogation
(if (<error>) return <error>;).

Here's a recent story to illustrate my point:

I recently used a Delphi library called Synapse that took this approach to
sockets - it had exceptions off by default and turned them on optionally. I
was using the call to obtain the results from an HTTPS post. Unfortunately,
Synapse had a bug in it [it has since been fixed] where if the OpenSSL dlls
could not be found, it would connect and *transmit* the form in clear text
instead of doing the usual SSL handshake and then encrypting the form. The
HTTPS server would of course then indicate that there was a problem and only
*then* would Synapse indicate failure to the caller with a return code.
Clearly this was a ***BIG SECURITY HOLE***. It was there because Synapse's
author forgot to check to see if OpenSSL loaded successfully.

Had the author of Synapse used exceptions exclusively, the function that
failed to load OpenSSL would have thrown an exception and the form would
never have been transmitted over the wire. In fact, the code would never
have even connected to the server.

Because of this experience, I try to never ever call a library that uses
error codes directly. Instead, I wrap the library and add a throw on
failure. It's a pain to write these cheesy little wrappers all over the
place, but the alternative is to replicate the error-code check everywhere.

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697
-- www.respower.com -- 500+ GHz Supercomputer Starting At USD$0.50/GHz*Hour

Alexander Terekhov

unread,
May 22, 2003, 8:37:04 AM5/22/03
to

Early Ehlinger wrote:
[...]

> An error is an error is an error.

No. "shall fail" POSIX errors are meant to be thrown as exceptions
but "may fail" POSIX errors are just *your* (or implementors) BUGS.

Here's an illustration (BTW, "more on this" can be found in my sig).

Imagine that we've got a <cthread> header that would provide (ala
<cstdlib> and qsort(), for example)

extern "C++" int pthread_key_create(pthread_key_t *, void (*)(void *));

(and etc.) to solve the {ugly-ugly-ugly} linkage problem. Now, here's
how the implementation of thread_specific_ptr could look (no_cleanup
overloading aside for a moment, and modulo bugs, of course):

#include <new> // for std::bad_alloc, std::try_again aside for a moment
#include <cthread>
#include <cassert>

struct no_cleanup { void operator()(void*) { } };

template<typename T, typename cleanup>
class thread_specific_ptr /* noncopyable [for now] */ {

static void TSD_dtor(void * p) {
cleanup()(static_cast<T *>(p));
}

pthread_key_t m_key;

public:

thread_specific_ptr() throw(std::bad_alloc/*, std::try_again*/) {
int status = std::pthread_key_create(&m_key, &TSD_dtor);
// throw std::bad_alloc if status == ENOMEM...
// throw std::try_again if status == EAGAIN...
assert(!status);
}

~thread_specific_ptr() throw() {
int status = std::pthread_key_delete(m_key);
assert(!status);
}

T * get() const throw() {
return static_cast<T *>(std::pthread_getspecific(m_key));
}

void set(T * p) const throw(std::bad_alloc) {
int status = std::pthread_setspecific(m_key, p);
// throw std::bad_alloc if status == ENOMEM...
assert(!status);
}

T * operator->() const throw() {
return get();
}

T & operator*() const throw() {
return *get();
}

T * release() throw() {
T * p = get();
if (p) set(0); // only an idiot will throw std::bad_alloc here
return p;
}

void reset(T * p = 0) throw(std::bad_alloc) {
T * old_p = get();
if (old_p != p) {
set(p);
cleanup()(old_p);
}
}

};

regards,
alexander.

--
http://tinyurl.com/cdsj

Early Ehlinger

unread,
May 27, 2003, 7:47:14 PM5/27/03
to
"Alexander Terekhov" <tere...@web.de> wrote:
> Early Ehlinger wrote:
> [...]
> > An error is an error is an error.
>
> No. "shall fail" POSIX errors are meant to be thrown as exceptions
> but "may fail" POSIX errors are just *your* (or implementors) BUGS.

Who exactly meant that "shall fail" POSIX errors are to be thrown as
exceptions? POSIX? I doubt it; unlessed I missed something, POSIX has
no
concept of exceptions.

It seems to me that you haven't really made a distinction. If a "may
fail"
error is indeed a bug, then itshould be thrown as an exception so that
the
program containing the bug will fail gloriously :) Why would "may fail"
be
any different than "shall fail" in terms of

> Here's an illustration (BTW, "more on this" can be found in my sig).

I'm not sure how this code illustrates your point... Would you mind
being
more specific?

> T * release() throw() {
> T * p = get();
> if (p) set(0); // only an idiot will throw std::bad_alloc here
> return p;
> }

At the risk of being an idiot, I'm going to beg to differ.

set() uses pthread_setspecific, which only fails with [ENOMEM] when
insufficient memory exists to associate the value with the key (at least
according to opengroup.org).

So you're saying that if set(0) fails, then it's ok to just ignore the
error? If release() is meant to release ownership (in the same sense
that
auto_ptr<>::release() releases ownership) then this is a terrible thing
to
do. What you will be left with is two entities, "this" and "the
caller",
that both think they exclusively own "T*"!!! This is absolutely horrid
and
the epitomy of pure evil.

No, set() should indeed throw if pthread_setspecific fails for any
reason
whatsoever, because that means that set() failed to live up to its
contract - it was unable to update its thread-specific pointer
correctly.

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697
-- www.respower.com -- 500+ GHz Supercomputer Starting At
USD$0.50/GHz*Hour

Alexander Terekhov

unread,
May 28, 2003, 6:25:59 PM5/28/03
to

Early Ehlinger wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote:
> > Early Ehlinger wrote:
> > [...]
> > > An error is an error is an error.
> >
> > No. "shall fail" POSIX errors are meant to be thrown as exceptions
> > but "may fail" POSIX errors are just *your* (or implementors) BUGS.
>
> Who exactly meant that "shall fail" POSIX errors are to be thrown as
> exceptions? POSIX? I doubt it; unlessed I missed something, POSIX has
> no concept of exceptions.

POSIX (SUS) systems have a concept of thread cancelation and exit.
That's surely an exception in C++ or C-with-exceptions; do a search
on "pthread_cancel_e". ;-)

>
> It seems to me that you haven't really made a distinction. If a "may

> fail" error is indeed a bug, then it should be thrown as an exception

> so that the program containing the bug will fail gloriously :) Why
> would "may fail" be any different than "shall fail" in terms of
>
> > Here's an illustration (BTW, "more on this" can be found in my sig).
>
> I'm not sure how this code illustrates your point... Would you mind
> being more specific?

No problem. Imagine a system interface for TSD access that doesn't
throw anything and just returns "status" info:

typedef void * __TSD_key_t; // whatever

int __tsd_key_create(
__TSD_key_t *
, void (* dtor)(void *, void *), void *
) throw();

int __tsd_key_delete(
__TSD_key_t
) throw();

int __tsd_getspecific(
__TSD_key_t
, void * *
) throw();

int __tsd_setspecific(
__TSD_key_t
, void *
) throw();

Now let's try to develop a <thread>'s thread_specific_ptr<> beast:

namespace std {

struct no_cleanup {
void operator()(void *) {
// NOOP
}
};

template<typename cleanup>
bool no_TSD_cleanup(const cleanup &) throw() {
return false;
}

template<>
bool no_TSD_cleanup(const no_cleanup &) throw() {
return true;
}

template<typename T, typename cleanup>

class thread_specific_ptr : cleanup /* noncopyable */ {

__TSD_key_t __key;

static void dtor(void * data, void * THIS) {
static_cast<thread_specific_ptr*>(THIS)->
operator()(static_cast<T*>(data));
}

public:

thread_specific_ptr()
throw(std::bad_alloc, std::try_again);

thread_specific_ptr(const cleanup&)
throw(std::bad_alloc, std::try_again);

~thread_specific_ptr() throw();

T * get() throw();

void set(T *) throw(std::bad_alloc);

T * operator->() throw();

T * release() throw();

void dispose() throw();

void reset(T *) throw(std::bad_alloc);

};

}

Now, here's its possible implementation:

namespace std {

void throw_errno_exception(int error) { /* ... */ }

template<typename T, typename cleanup>

thread_specific_ptr<T, cleanup>::thread_specific_ptr()
throw(std::bad_alloc, std::try_again) {
int status = __tsd_key_create(&__key, no_TSD_cleanup(
*static_cast<cleanup*> (this)) ? 0 : &dtor, this);
if (status) throw_errno_exception(status);
}

template<typename T, typename cleanup>

thread_specific_ptr<T, cleanup>::thread_specific_ptr(
const cleanup& __cleanup) throw(std::bad_alloc,
std::try_again) : cleanup(__cleanup) {
int status = __tsd_key_create(&__key, no_TSD_cleanup(
__cleanup) ? 0 : &dtor, this);
if (status) throw_errno_exception(status);
}

template<typename T, typename cleanup>

thread_specific_ptr<T, cleanup>::~thread_specific_ptr()
throw() {
int status = __tsd_key_delete(__key);
if (status) throw_errno_exception(status);
}

template<typename T, typename cleanup>

T * thread_specific_ptr<T, cleanup>::get() throw() {
void * p;
int status = __tsd_getspecific(__key, &p);
if (status) throw_errno_exception(status);
return p;
}

template<typename T, typename cleanup>

void thread_specific_ptr<T, cleanup>::set(T* p)
throw(std::bad_alloc) {
int status = __tsd_setspecific(__key, p);
if (status) throw_errno_exception(status);
}

template<typename T, typename cleanup>

T * thread_specific_ptr<T, cleanup>::release() throw() {
void * p = get();
set(0);
return p;
}

template<typename T, typename cleanup>

void thread_specific_ptr<T, cleanup>::dispose() throw() {
this->cleanup::operator()(release());
}

template<typename T, typename cleanup>

void thread_specific_ptr<T, cleanup>::reset(T* p)
throw(std::bad_alloc) {
void * old_p = get();


if (old_p != p) {
set(p);

this->cleanup::operator()(old_p);
}
}

}

Now, the only thing that's still missing is a <cthread> layer...

Here we go:

// Possible implementation for <cthread>
#include <thread>

namespace std {

extern "C" typedef void (* __c_TSD_dtor_t)(void *);
extern "C++" typedef void (* __cpp_TSD_dtor_t)(void *);

struct __cthread_TSD_cleanup {

__cthread_TSD_cleanup(__c_TSD_dtor_t __c_TSD_dtor_) :
__func(__c_TSD_dtor_ ? c : null),
__c_TSD_dtor(__c_TSD_dtor_) {
}

__cthread_TSD_cleanup(__cpp_TSD_dtor_t __cpp_TSD_dtor_) :
__func(__cpp_TSD_dtor_ ? cpp : null),
__cpp_TSD_dtor(__cpp_TSD_dtor_) {
}

void operator()(void * __data) {
if (__data) switch(__func) {
case c: __c_TSD_dtor(__data); break;
case cpp: __cpp_TSD_dtor(__data); break;
}
}

enum { null, c, cpp } __func;

union {
__c_TSD_dtor_t __c_TSD_dtor;
__cpp_TSD_dtor_t __cpp_TSD_dtor;
};

};

template<>
bool no_TSD_cleanup(const __cthread_TSD_cleanup & __cleanup)
throw() {
return __cleanup.__func == __cthread_TSD_cleanup::null;
}

typedef std::thread_specific_ptr<void, __cthread_TSD_cleanup> *
pthread_key_t;

// try { throw; } catch... "idiom"
int __translate_exception_to_error_code() throw();

extern "C" int pthread_key_create(pthread_key_t * key,
void ( * dtor)(void *)) throw() {
try {
// can throw "shall fail" stuff only (std::bad_alloc and
// std::try_again)
*key = new std::thread_specific_ptr<void,
__cthread_TSD_cleanup>(__cthread_TSD_cleanup(dtor));
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
}
catch(...) {
return __translate_exception_to_error_code();
}
return 0;
}

extern "C++" int pthread_key_create(pthread_key_t * key,
void ( * dtor)(void *)) throw() {
try {
// can throw "shall fail" stuff only (std::bad_alloc and
// std::try_again)
*key = new std::thread_specific_ptr<void,
__cthread_TSD_cleanup>(__cthread_TSD_cleanup(dtor));
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
}
catch(...) {
return __translate_exception_to_error_code();
}
return 0;
}

extern "C" int pthread_key_delete(pthread_key_t key) throw() {
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
delete key;
return 0;
}

extern "C" void * pthread_getspecific(pthread_key_t key) throw() {
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
return key->get();
}

extern "C" int pthread_setspecific(pthread_key_t key,
const void * p) throw(std::bad_alloc) {
try {
// can throw "shall fail" stuff only (std::bad_alloc)
key->set(const_cast<void *>(p));
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
}
catch(...) {
return __translate_exception_to_error_code();
}
return 0;
}

extern "C" int pthread_resetspecific(pthread_key_t key,
const void * p) throw(std::bad_alloc) {
try {
// can throw "shall fail" stuff only (std::bad_alloc)
key->reset(const_cast<void *>(p));
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
}
catch(...) {
return __translate_exception_to_error_code();
}
return 0;
}

extern "C" void * pthread_releasespecific(pthread_key_t key) throw() {
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
return key->release();
}

extern "C" void pthread_disposespecific(pthread_key_t key) throw() {
// "may fail" shall be caught in the std::unexpected() handler
// for details... please click here: <http://tinyurl.com/cu9k>
return key->dispose();
}

}

("or something like that")

Do you understand it now? ;-)

>
> > T * release() throw() {
> > T * p = get();
> > if (p) set(0); // only an idiot will throw std::bad_alloc here
> > return p;
> > }
>
> At the risk of being an idiot, I'm going to beg to differ.
>
> set() uses pthread_setspecific, which only fails with [ENOMEM] when
> insufficient memory exists to associate the value with the key (at
> least according to opengroup.org).
>
> So you're saying that if set(0) fails, then it's ok to just ignore
> the error? If release() is meant to release ownership (in the same
> sense that auto_ptr<>::release() releases ownership) then this is a
> terrible thing to do. What you will be left with is two entities,
> "this" and "the caller", that both think they exclusively own "T*"!!!
> This is absolutely horrid and the epitomy of pure evil.

Please follow the links:

http://lists.boost.org/MailArchives/boost/msg47702.php
(Subject: [boost] Re: thread lib: thread specific storage problem)

Thank you.

regards,
alexander.

--
"// Possible implementation for <pthread.h> and <cthread>
#include <thread>
// for <cthread>, please remove the using-directive
using namespace std;"
-- "alt"

Emil Dotchevski

unread,
May 29, 2003, 11:41:59 AM5/29/03
to
> An error is an error is an error.

Not every problem should throw an exception. The decision to throw an
exception depends on the viewpoint, and it is up to the library
designer to figure out. Some conditions call for using an error code
to report them, and others are best caught using the assert macro.
Using exceptions exclusively is wrong, however exceptions should not
be avoided when they are appropriate.

> If your program doesn't handle it (even if handling it means explicitly
> ignoring it with catch(<condition>){} ), you've got a bug.

But using try...catch may also hide problems. Good code uses very few
try...catch blocks; in addition, using try...catch as means of
ignoring an exception is almost always an indication that the decision
to throw an exception in this case was not justified.

> You might argue
> to me that implicitly ignoring it is perfectly suitable.

Again, this depends on the concrete problem. When a given unpleasent
condition is detected, it may be appropriate to throw an exception in
one program but use other means of dealing with the same problem at
other times.

> I will grant that exceptions
> *can* cause additional overhead, but they certainly do not *have to* and can
> even reduce overhead by minimizing the need for explicit error propogation
> (if (<error>) return <error>;).

If the desired behavior of a piece of code is to do

if( error ) return error;

then most likely an exception is what you need instead, but in this
case try...catch should only be used at a higher level, typically
where the operation that failed was initiated.

But again, the use of exceptions should be carefully weighted against
other possibilities. For example, anything that indicates a logical
error in your code should be an assertion, and std::logical_error
exceptions should never be used instead.

> Because of this experience, I try to never ever call a library that uses
> error codes directly. Instead, I wrap the library and add a throw on
> failure.

But it depends on the definition of failure, which depends on the
problem you are solving. If a TCP/IP socket has disconnected, throwing
an exception makes sense if you want to provide a clean way of undoing
everything that occured after the data transfer started.
Alternatively, it may be more appropriate for the same condition to
simply cause the library to ignore all future requests for data
transfer and provide an error code to indicate the failure.

As another example, it is probably silly for a logging function to
throw an exception if it failed to log something. Instead, after the
entire operation has finished, you simply ask the library if the log
was successfully created, and notify the user if there was a problem.

C++ programming is hard. There are no simple rules that guarantee good
results.

--Emil

Early Ehlinger

unread,
May 31, 2003, 6:33:11 PM5/31/03
to
"Emil Dotchevski" <em...@collectivestudios.com> wrote:
> But using try...catch may also hide problems. Good code uses very few
> try...catch blocks;

Good code /should/ have very few try/catch blocks. In fact it
should have very close to 0 and instead rely on being exception-safe to
the maximum extent possible.


> in addition, using try...catch as means of
> ignoring an exception is almost always an indication that the decision
> to throw an exception in this case was not justified.

Agreed. This is why I started with "even if". It is exceedingly rare that
ignoring an error is the "right thing to do." It is so rare, in fact, that
this is why I say that errors should always be reported via exceptions;
exceptions cannot be implicitly ignored, so explicitly ignoring them with
try/catch will stand out as being "odd" and will beg for justification.
Forgetting to check a return code will not seem odd on review, except to the
most careful people on the planet.

> > Because of this experience, I try to never ever call a library that uses
> > error codes directly. Instead, I wrap the library and add a throw on
> > failure.
>
> But it depends on the definition of failure, which depends on the
> problem you are solving. If a TCP/IP socket has disconnected, throwing
> an exception makes sense if you want to provide a clean way of undoing
> everything that occured after the data transfer started.

Er, I assume you mean everything that occured after the connection was
disconnected?

> Alternatively, it may be more appropriate for the same condition to
> simply cause the library to ignore all future requests for data
> transfer and provide an error code to indicate the failure.

This is pure, anadulterated evil. The error code is way too likely to be
accidentally ignored and lead to the exact problem that I listed in my
original response to this thread. Any library that "simply ignores"
anything I ask of it is evil. It can be redeemed with a wrapper that throws
exceptions, of course....

> As another example, it is probably silly for a logging function to
> throw an exception if it failed to log something. Instead, after the
> entire operation has finished, you simply ask the library if the log
> was successfully created, and notify the user if there was a problem.

This is the first counterexample I've seen on this thread that (almost)
makes sense. If I've got a debug log that fails to write to the log, I
don't necessarily want to spend my time figuring out why it crashed. On the
other hand, I've had debug logs that (silently) failed to write to the log
in the past, and I can tell you that it is incredibly frustrating to make
changes to your code and see the exact same log file come back because the
program didn't report a failure to write to the log.

So I'm still going to have to go with the old rule of thumb: if a function
cannot do what it says it will do, it should throw an exception.

>
> C++ programming is hard. There are no simple rules that guarantee good
> results.

Of course C++ programming is hard. All programming is hard, and every rule
has at least one counterexample. (In the case of that rule, it is its own
counterexample...)

In the case of "failure should lead to throw," my favorite counterexample is
that of external forces. Suppose, for example, that you are writing a COM
object that will be called from Visual Basic. Is there a chance in hell
that VB is going to understand a C++ exception? No, so you need to make
sure that every method on your COM object catches all exceptions, sets up
the IErrorInfo stuff properly, and returns an appropriate HRESULT so that VB
will read the IErrorInfo stuff and generate a useful Error object (which
happens to be the VB analogue to exceptions).

But even in this situation, I still prefer for the layers below COM to use
exceptions to report any failures; I simply have each method look like this:

HRESULT ComLayerImpl::Method( )
{
try
{
m_lower_layer.method();
return S_OK;
}
catch(std::exception& ) { translate_std_exception(); return failure_code; }
catch(...) { translate_unrecognized_exception(); return failure_code; }
}

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697
-- www.respower.com -- 500+ GHz Supercomputer Starting At USD$0.50/GHz*Hour

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Jun 1, 2003, 8:51:21 AM6/1/03
to
In message <vdi88oq...@corp.supernews.com>, Early Ehlinger
<ea...@respower.com> writes

>Of course C++ programming is hard. All programming is hard, and every
rule
>has at least one counterexample. (In the case of that rule, it is its
own
>counterexample...)

But hard like learning to write completely correct English is hard
(indeed even defining completely correct English is hard:-) I sometimes
wish that programmers would stop using the mantra 'Programming is hard.'

with its unspoken completion 'I am a programmer, hence I am brilliant.'

Programming, even in C++, is no harder than many other things we do. And

like those many other things, people who are not deterred by the claim
that it is hard find they can do, find useful and even enjoy, simple
programming even if they cannot write a major application.


--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow ACCU

Early Ehlinger

unread,
Jun 2, 2003, 5:26:00 AM6/2/03
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote:
> I sometimes wish that programmers would stop
> using the mantra 'Programming is hard.'
> with its unspoken completion 'I am a programmer, hence I am brilliant.'

I certainly hope I didn't come off as being that arrogant. Although I'm
confident in my intelligence, I don't place myself on the pedestal of being
brilliant. Of course, that's something I strive toward, but I've got an
exceptionally long way to go still.

> Programming, even in C++, is no harder than many other things we do. And
> like those many other things, people who are not deterred by the claim
> that it is hard find they can do, find useful and even enjoy, simple
> programming even if they cannot write a major application.

Actually, programming *is* harder than many other things we do. It's a
helluva lot harder. Does that mean people shouldn't give it a try, even on a
casual "do-it-yourself" basis? Certainly not. Its difficulty is precisely
what makes it enjoyable.

I skateboard recreationally and find it quite enjoyable even though I know I
will never attain the level of skill that the masters of that sport enjoy.
But I enjoy it /because/ it's difficult to do, and there's always room for
progression, no matter how good I get at it. And no matter how good I get
at skateboarding, there is always the possibility that I will hit a tiny
pebble that will cause my board to stop beneath my feet, throwing me
hurtling to the ground.

Programming is the same way. No matter how skilled I become, there will
always be room for improvement and there will always be subtle things to
trip me up. Just the other day, for example, I had an object that was
stored in a std::vector do a push_back on the vector that contained it.
Most of the time it worked just fine, but every now and then the vector
would have the audacity to expand its capacity in response to push_back. A
tiny pebble indeed, and I should've seen it before I even wrote the code.
But instead, it threw me to the ground it took nearly the whole afternoon to
finally figure out why my object suddenly seemed invalid for no apparent
reason.

If programming were not hard, I would quit today and find something else
that was hard.

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697
-- www.respower.com -- 500+ GHz Supercomputer Starting At USD$0.50/GHz*Hour

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Early Ehlinger

unread,
Jun 2, 2003, 2:38:34 PM6/2/03
to
"Alexander Terekhov" wrote:
> Early Ehlinger wrote:
> > "Alexander Terekhov" wrote:
> > > Early Ehlinger wrote:
> > > [...]
> > > > An error is an error is an error.
> > >
> > > No. "shall fail" POSIX errors are meant to be thrown as exceptions
> > > but "may fail" POSIX errors are just *your* (or implementors) BUGS.
> >
> > Who exactly meant that "shall fail" POSIX errors are to be thrown as
> > exceptions? POSIX? I doubt it; unlessed I missed something, POSIX has
> > no concept of exceptions.
>
> POSIX (SUS) systems have a concept of thread cancelation and exit.
> That's surely an exception in C++ or C-with-exceptions; do a search
> on "pthread_cancel_e". ;-)

Thread cancelation is certainly not an exception. It's a means for asking a
thread to exit. An exception is a means for transferring control to the
exception-processing mechanism (stack unwinder).

> > > Here's an illustration (BTW, "more on this" can be found in my sig).
> >
> > I'm not sure how this code illustrates your point... Would you mind
> > being more specific?

Please allow me to rephrase my question. I'm not bright enough to see a
ream of code and zillions of links and suddenly "get it". I spent quite a
bit of time following all of the links you included in your code and trying
to decipher how those links had anything to do with the general
rule-of-thumb that functions should prefer exceptions to error codes to
indicate failure.

In fact, in one of the links in your code - http://tinyurl.com/cu9k -,
Terje SlettebÅ™ made the following observation that I feel compelled to
reiterate.

: I've read through your postings, but as they are long and
: detailed, with a lot of references to other places, but
: without some kind of introduction or summary, I found
: it hard to understand what your point was.

So here is my rephrased question. Could you offer a minimal code sample of
a function that fails to perform its -er- function and must not throw an
exception, with a "prose" explaination as to why it is preferrable to not
throw an exception?

I know that there are exceptions to the general rule-of-thumb. Elsewhere on
this thread, I offered COM as a prime example - a COM method cannot
guarantee that it is being called from a C++ environment that can even
understand exceptions and is therefore forced to return an error code. But
even when writing a COM component, I prefer to split the development in
two - a COM layer that provides COM interoperability, and a C++-only layer.
The COM layer has each method catch all exceptions and translate them into
information for the COM client to query via IErrorInfo.

So the architecture ends up looking like this:

[ COM Client ]
<-- error codes
[ COM Server ]
<-- exceptions
[ C++ Implementation ]
{ exceptions internally }


> ("or something like that")
>
> Do you understand it now? ;-)

No. Information overload.

>
> >
> > > T * release() throw() {
> > > T * p = get();
> > > if (p) set(0); // only an idiot will throw std::bad_alloc here
> > > return p;
> > > }
> >
> > At the risk of being an idiot, I'm going to beg to differ.
> >
> > set() uses pthread_setspecific, which only fails with [ENOMEM] when
> > insufficient memory exists to associate the value with the key (at
> > least according to opengroup.org).
> >
> > So you're saying that if set(0) fails, then it's ok to just ignore
> > the error? If release() is meant to release ownership (in the same
> > sense that auto_ptr<>::release() releases ownership) then this is a
> > terrible thing to do. What you will be left with is two entities,
> > "this" and "the caller", that both think they exclusively own "T*"!!!
> > This is absolutely horrid and the epitomy of pure evil.
>
> Please follow the links:
>
> http://lists.boost.org/MailArchives/boost/msg47702.php
> (Subject: [boost] Re: thread lib: thread specific storage problem)

As you point out in your defect report

http://opengroup.org/austin/mailarchives/austin-review-l/msg01511.html

This might die in std::unexpected due to set(0). I didn't notice the
throw() before.

IMHO, this interface is broken; it makes a promise that release() will never
fail, when in fact it can fail. Perhaps I should re-write that last
sentence a little differently. This interface is broken; it makes a promise
that release() will never fail, when in fact it will fail, at the most
inopportune moment.

release() should be declared to throw( std::badalloc ), if you're hell-bent
on using ES, or to not have an ES at all.

Note that I don't make the statement that the interface is broken lightly.
release() depends (eventually) on pthread_setspecific, which can fail in one
of two ways:

From
http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_setspecific.html
: The pthread_setspecific() function will fail if:
: [ENOMEM]
: Insufficient memory exists to associate the value with the key.
:
: The pthread_setspecific() function may fail if:
: [EINVAL]
: The key value is invalid.

There is no indication as to what could ultimately cause ENOMEM. In other
words, there is no guarantee that calling it with value == 0 will not result
in ENOMEM. Therefore you must assume that it will result in ENOMEM at the
least opportune moment possible, after you've tested your code and shipped
it off to your customer. So you cannot make a promise that release() will
never fail, because it will fail!

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697
-- www.respower.com -- 500+ GHz Supercomputer Starting At USD$0.50/GHz*Hour

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alexander Terekhov

unread,
Jun 3, 2003, 5:18:01 AM6/3/03
to

Early Ehlinger wrote:
[...]
> > > > > An error is an error is an error.
> > > >
> > > > No. "shall fail" POSIX errors are meant to be thrown as exceptions
> > > > but "may fail" POSIX errors are just *your* (or implementors) BUGS.
> > >
> > > Who exactly meant that "shall fail" POSIX errors are to be thrown as
> > > exceptions? POSIX? I doubt it; unlessed I missed something, POSIX has
> > > no concept of exceptions.
> >
> > POSIX (SUS) systems have a concept of thread cancelation and exit.
> > That's surely an exception in C++ or C-with-exceptions; do a search
> > on "pthread_cancel_e". ;-)
>
> Thread cancelation is certainly not an exception. It's a means for asking a
> thread to exit. An exception is a means for transferring control to the
> exception-processing mechanism (stack unwinder).

An exception is a means for transferring control to either catch
handler or std::unexpected() handler (bypassing std::unexpected() and
going directly to std::terminate() aside for a moment). Well, I guess
you might want to spend some time following the embedded links here:

http://lists.boost.org/MailArchives/boost/msg47672.php
http://lists.boost.org/MailArchives/boost/msg47699.php
(Subject: [boost] Re: New linux thread impl needed for NPTL?)

>
> > > > Here's an illustration (BTW, "more on this" can be found in my sig).
> > >
> > > I'm not sure how this code illustrates your point... Would you mind
> > > being more specific?
>
> Please allow me to rephrase my question. I'm not bright enough to see a
> ream of code and zillions of links and suddenly "get it". I spent quite a
> bit of time following all of the links you included in your code and trying
> to decipher how those links had anything to do with the general
> rule-of-thumb that functions should prefer exceptions to error codes to
> indicate failure.
>
> In fact, in one of the links in your code - http://tinyurl.com/cu9k -,

> Terje Sletteb made the following observation that I feel compelled to


> reiterate.
>
> : I've read through your postings, but as they are long and
> : detailed, with a lot of references to other places, but
> : without some kind of introduction or summary, I found
> : it hard to understand what your point was.

For the record, my answer to that challenge can be found here:

http://groups.google.com/groups?selm=3ED3AE8B.AEDAD52A%40web.de
(Subject: Re: Exception handling... it's time to fix the standard)

>
> So here is my rephrased question. Could you offer a minimal code sample of
> a function that fails to perform its -er- function and must not throw an
> exception, with a "prose" explaination as to why it is preferrable to not
> throw an exception?

"asserts"/"may fail"/"bugs" shall not be propagated to callers.
Everything else is totally okay to propagate so that callers
can catch-handle-it-and-continue (or do whatever they want).

[...]


> As you point out in your defect report
>
> http://opengroup.org/austin/mailarchives/austin-review-l/msg01511.html
>
> This might die in std::unexpected due to set(0). I didn't notice the
> throw() before.
>
> IMHO, this interface is broken; it makes a promise that release() will never
> fail, when in fact it can fail. Perhaps I should re-write that last
> sentence a little differently. This interface is broken; it makes a promise
> that release() will never fail, when in fact it will fail, at the most
> inopportune moment.

Nah, throw()-nothing release() IS okay. The current
pthread_setspecific() is broken. It shall NOT fail with ENOMEM for
null pointers.

>
> release() should be declared to throw( std::badalloc ), if you're hell-bent
> on using ES, or to not have an ES at all.
>
> Note that I don't make the statement that the interface is broken lightly.
> release() depends (eventually) on pthread_setspecific, which can fail in one
> of two ways:
>
> From
> http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_setspecific.html
> : The pthread_setspecific() function will fail if:
> : [ENOMEM]
> : Insufficient memory exists to associate the value with the key.
> :
> : The pthread_setspecific() function may fail if:
> : [EINVAL]
> : The key value is invalid.

"may fail" is a bug -- it shall never be propagated.

>
> There is no indication as to what could ultimately cause ENOMEM. In other
> words, there is no guarantee that calling it with value == 0 will not result
> in ENOMEM. Therefore you must assume that it will result in ENOMEM at the
> least opportune moment possible, after you've tested your code and shipped
> it off to your customer. So you cannot make a promise that release() will
> never fail, because it will fail!

Just wait for POSIX.1-2001 TC2. In the meantime, you might want to
take a look at: (Subject: Re: pthread_key_delete(): a defect?)

http://opengroup.org/austin/mailarchives/austin-group-l/msg04522.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04523.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04524.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04525.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04526.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04527.html
http://opengroup.org/austin/mailarchives/austin-group-l/msg04528.html

regards,
alexander.

Ben Hutchings

unread,
Jun 3, 2003, 2:59:39 PM6/3/03
to
In article <vdmo3bq...@corp.supernews.com>, Early Ehlinger wrote:
> "Alexander Terekhov" wrote:
>> Early Ehlinger wrote:
>> > "Alexander Terekhov" wrote:
>> > > Early Ehlinger wrote:
>> > > [...]
>> > > > An error is an error is an error.
>> > >
>> > > No. "shall fail" POSIX errors are meant to be thrown as exceptions
>> > > but "may fail" POSIX errors are just *your* (or implementors) BUGS.
>> >
>> > Who exactly meant that "shall fail" POSIX errors are to be thrown as
>> > exceptions? POSIX? I doubt it; unlessed I missed something, POSIX has
>> > no concept of exceptions.
>>
>> POSIX (SUS) systems have a concept of thread cancelation and exit.
>> That's surely an exception in C++ or C-with-exceptions; do a search
>> on "pthread_cancel_e". ;-)
>
> Thread cancelation is certainly not an exception. It's a means for asking a
> thread to exit. An exception is a means for transferring control to the
> exception-processing mechanism (stack unwinder).

I think Alexander's point (which I wish he would just make clearly) is that
when a thread is cancelled it should be cleaned up. In the C API to POSIX
threads this is done by registering clean-up functions. In C++ we clean up
a chain of execution by throwing an exception.

The problem I see is that an exception might be caught, whereas, if I
remember correctly, there is no way for cancellation to be prevented by a
clean-up function.

Early Ehlinger

unread,
Jun 3, 2003, 3:05:20 PM6/3/03
to
"Alexander Terekhov" <tere...@web.de> wrote

> > Thread cancelation is certainly not an exception. It's a means for
asking a
> > thread to exit. An exception is a means for transferring control to
the
> > exception-processing mechanism (stack unwinder).
>
> An exception is a means for transferring control to either catch
> handler or std::unexpected() handler (bypassing std::unexpected() and
> going directly to std::terminate() aside for a moment).

6-in-one hand, a half-dozen in the other. The exception processing
mechanism looks for a catch handler and if it cannot find one in place, it
calls std::unexpected. The links you posted this time seem to be complaints
by you that pthreads doesn't implement pthread_cancel/exit by throwing a C++
exception inside of the thread being cancelled. While that ***might*** be a
nice thing to have for C++ programmers, pthreads is not a C++ only sandbox,
so I doubt you'll see /that/ any time soon. So the difference is still
there - thread cancellation is *not* an exception.

> > Terje Slettebo [wrote previously]:


> > : I've read through your postings, but as they are long and
> > : detailed, with a lot of references to other places, but
> > : without some kind of introduction or summary, I found
> > : it hard to understand what your point was.
> For the record, my answer to that challenge can be found here:

I saw your answer the first time. My intent in quoting Terje Slettebo was
to get you to please stop delluging me with links that are all moderately
related to the current discussion but have no *direct* bearing on it. As I
said, I'm not bright enough to read all of this information and suddenly get
what it has to do with a general rule-of-thumb about preferring exceptions
over error codes.

> > So here is my rephrased question. Could you offer a minimal code
sample of
> > a function that fails to perform its -er- function and must not throw
an
> > exception, with a "prose" explaination as to why it is preferrable to
not
> > throw an exception?
>
> "asserts"/"may fail"/"bugs" shall not be propagated to callers.
> Everything else is totally okay to propagate so that callers
> can catch-handle-it-and-continue (or do whatever they want).

I'll kind of buy asserts, although I *generally* believe that exceptions
should be preferred to assertions. In high-performance code, however, the
benefits of turning assert off can outweigh the cost of losing the
error-checking in the release version.

With "may fail", I'm still going to have to part ways with you. Unless I'm
being totally dense, "may fail" is used to specify that an implementation of
an interface is allowed to fail in the "may fail" manner, whereas "shall
fail" is used to specify that an implementation of an interface is required
to fail under a certain set of circumstances. In either case, once the
failure has occurred, it *has occurred* and *must* be dealt with. Unless it
can be dealt with immediately at the site where the failure occured, it
should be reported via exception.

What exactly do you mean by "bugs"? When I say "bug" I mean an unintended
failure in the code. By virtue of its being unintended, you do not know
where or how it will be propagated. It could lead to core-dump. Could lead
to corrupted database. Who knows... Granted, you ideally want to minimize
the possible effect of your "bug" or elliminate the possibility of
introducing it entirely. In fact, this whole branch of the thread is
revolving around the possibility of eliminating an entire class of bugs
(unintentionally ignored error codes) by using exceptions exclusively to
report failures.

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697 --

- RenderFarm - Lightwave , 3dSMax , Bryce , Maya , AfterEffects -
--- www.respower.com -- 500+ GHz Starting At USD$0.50/GHz*Hour --
----------------- SuperComputing For the Masses! ----------------
"I'm so busy programming my computer to let me be lazy, I never
get any rest!" - John Kaster

Ben Hutchings

unread,
Jun 4, 2003, 2:00:50 PM6/4/03
to
In article <vdp7dg1...@corp.supernews.com>, Early Ehlinger wrote:
> "Alexander Terekhov" <tere...@web.de> wrote
>> > Thread cancelation is certainly not an exception. It's a means for
>> > asking a thread to exit. An exception is a means for transferring
>> > control to the exception-processing mechanism (stack unwinder).
>>
>> An exception is a means for transferring control to either catch
>> handler or std::unexpected() handler (bypassing std::unexpected() and
>> going directly to std::terminate() aside for a moment).
>
> 6-in-one hand, a half-dozen in the other. The exception processing
> mechanism looks for a catch handler and if it cannot find one in place, it
> calls std::unexpected. The links you posted this time seem to be complaints
> by you that pthreads doesn't implement pthread_cancel/exit by throwing a C++
> exception inside of the thread being cancelled. While that ***might*** be a
> nice thing to have for C++ programmers, pthreads is not a C++ only sandbox,
> so I doubt you'll see /that/ any time soon. So the difference is still
> there - thread cancellation is *not* an exception.
<snip>

Pthreads is a standard and not an implementation. Some implementations of
it (at least those in Solaris and Tru64) already do throw an exception on
cancellation, glibc will probably do so soon, and it seems to be generally
considered the right thing to do. So maybe it would be a good idea to
standardise this behaviour.

Alexander Terekhov

unread,
Jun 4, 2003, 2:01:44 PM6/4/03
to

Early Ehlinger wrote:
[...]

> With "may fail", I'm still going to have to part ways with you. Unless I'm
> being totally dense, "may fail" is used to specify that an implementation of
> an interface is allowed to fail in the "may fail" manner, whereas "shall
> fail" is used to specify that an implementation of an interface is required
> to fail under a certain set of circumstances. ...

http://www.opengroup.org/onlinepubs/007904975/functions/pthread_mutex_destroy.html

<quote>

Tradeoff Between Error Checks and Performance Supported

Many of the error checks were made optional in order to let
implementations trade off performance versus degree of error
checking according to the needs of their specific applications
and execution environment. As a general rule, errors or
conditions caused by the system (such as insufficient memory)
always need to be reported, but errors due to an erroneously
coded application (such as failing to provide adequate
synchronization to prevent a mutex from being deleted while
in use) are made optional.

A wide range of implementations is thus made possible. For
example, an implementation intended for application debugging
may implement all of the error checks, but an implementation
running a single, provably correct application under very
tight performance constraints in an embedded computer might
implement minimal checks. An implementation might even be
provided in two versions, similar to the options that
compilers provide: a full-checking, but slower version;
and a limited-checking, but faster version. To forbid this
optionality would be a disservice to users.

By carefully limiting the use of "undefined behavior" only
to things that an erroneous (badly coded) application might
do, and by defining that resource-not-available errors are
mandatory, this volume of IEEE Std 1003.1-2001 ensures that
a fully-conforming application is portable across the full
range of implementations, while not forcing all
implementations to add overhead to check for numerous things
that a correct program never does.

</quote>

regards,
alexander.

Alexander Terekhov

unread,
Jun 5, 2003, 3:23:09 AM6/5/03
to

Ben Hutchings wrote:
[...]

> The problem I see is that an exception might be caught, whereas, if I
> remember correctly, there is no way for cancellation to be prevented by a
> clean-up function.

That's correct. A reasonable C++ implementation of posix cleanup API
is nothing but <http://tinyurl.com/dgf6>:

#define pthread_cleanup_push(routine,arg) \
{ \
ScopeGuard _guard = MakeObjGuard(arg,routine);

#define pthread_cleanup_pop(execute) \
if (!execute) _guard.Dismiss(); \
}

(or something like that).

This doesn't mean that you can't catch and finalize thread cancel
exception. Think of "futures" and "executors"... Why would you want
to recycle a thread [from a pool of workers] if all you want is to
cancel this or that "future" that just happens to be already-served
[busy/in execution] by some thread that performs some cancelable/
blocking operation(s) on behalf of "future"? Well, it is true that
the current standard has some problems with respect to catching-
and-finalizing thread cancelation (and exit):

http://opengroup.org/austin/mailarchives/austin-group-l/msg05202.html
http://opengroup.org/austin/mailarchives/austin-review-l/msg01449.html
http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html
http://opengroup.org/austin/mailarchives/austin-review-l/msg01451.html

regards,
alexander.

--
"Perhaps that would provide an opportunity for a smaller POSIX
project, though; a PROFILE that would chink the holes where the
two walls meet. In effect, specifying a "POSIX platform"
supporting both threads and C++ that simply says "C++
cancellation is the same as POSIX cancellation", "POSIX cleanup
handlers are logically and semantically the same as C++ object
destructors", and "POSIX cancellation is visible as a C++
exception"." -- <http://tinyurl.com/dggr>

Early Ehlinger

unread,
Jun 9, 2003, 2:54:40 PM6/9/03
to
"Alexander Terekhov" <tere...@web.de> wrote :

>
> Early Ehlinger wrote:
> [...]
> > With "may fail", I'm still going to have to part ways with you.
Unless
I'm
> > being totally dense, "may fail" is used to specify that an
implementation of
> > an interface is allowed to fail in the "may fail" manner, whereas
"shall
> > fail" is used to specify that an implementation of an interface is
required
> > to fail under a certain set of circumstances. ...
>
> Tradeoff Between Error Checks and Performance Supported

The stuff you quoted explains the "why" as to the difference between may
fail and shall fail; thank you for the enlightenment. They indeed do
mean
what I thought they meant, but it's always nice to understand why as
well.

My argument is this: Once the pthread implementation *HAS FAILED*,
whether
it was a failure that it was required to produce (shall fail) or one
that it
was allowed to produce (may fail), it *HAS FAILED*. We are no longer in
the
realm of deciding whether or not there is a failure: the failure has
occurred and must be dealt with.

The question becomes this: If you are implementing a C++ wrapper layer
for
pthreads, should you report this failure with an error code, or with an
exception?

If I've understood you correctly, your vote is that it depends on
whether
the failure was one that the implementation was required to generate
(shall
fail) or one that the implementation was allowed to generate (may fail).
In
the case of shall fail, throw an exception. In the case of may fail, do
not
throw an exception.

I don't understand your rationale for this - apparently the mere fact
that
the implementation is not *required* to generate the failure is enough
for
you to allow the possibility of the failure being ignored by the
application
layer.

My vote is clearly that it doesn't matter how the code got to the point
of
failure; it has failed and that failure must not be ignored. You should
therefore report it as an exception, because otherwise it is likely that
the
developer using the wrapper layer will in all likelihood accidentally
ignore the failure, and the application will silently run off into
the weeds.

--
-- Early Ehlinger CEO, ResPower Inc - Toll-Free : 866-737-7697

-- www.respower.com -- 500+ GHz Supercomputer Starting At
USD$0.50/GHz*Hour

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alexander Terekhov

unread,
Jun 10, 2003, 12:53:09 PM6/10/03
to

Early Ehlinger wrote:
[...]

> The question becomes this: If you are implementing a C++ wrapper
> layer for pthreads, should you report this failure with an error
> code, or with an exception?
>
> If I've understood you correctly, your vote is

My vote is for std0X::expected_exception<T>().

http://google.com/groups?threadm=3EE08DDC.A3A7A32D%40web.de
(Subject: std0X::expected_exception<T>())

> that it depends on
> whether the failure was one that the implementation was required
> to generate (shall fail) or one that the implementation was allowed
> to generate (may fail). In the case of shall fail, throw an exception.

> In the case of may fail, do not throw an exception.

Rather: don't propagate bugs (unexpected errors). You should either
"assert" and/or do a "bugcheck" for them... or "translate" everything
to exceptions and use repaired** exception specifications that would
"force" std::unexpected() for bugs (aka well, unexpected exceptions)
not causing any unwinding. That's what the "example" I've posted here
attempted to "demonstrate".

regards,
alexander.

**) "for details... please click here: <http://tinyurl.com/cu9k>"

0 new messages