[boost::throw_exception] and platforms where it don't throw

Hi All, I'm about to replace all my throw Foo; statetements in the Pointer Container library with something else to support platforms without exceptions. Is using boost::throw_exception the way to do it? If I where on such a platform, I kinda think that I would have preferred an assertion *at the throw spot* instead of making the call stack deeper yet and then call about or something. Thanks for any feedback -Thorsten

Thorsten Ottosen wrote:
Hi All,
I'm about to replace all my throw Foo; statetements in the Pointer Container library with something else to support platforms without exceptions.
Is using boost::throw_exception the way to do it?
If I where on such a platform, I kinda think that I would have preferred an assertion *at the throw spot* instead of making the call stack deeper yet and then call about or something.
If it is not a throw expression it ought to be something with similar semantics, such as a function with __attribute__((__noreturn__)) (or whatever it is spelled for a particular compiler), so the compiler knows that no code past this point is ever executed. Else you may get spurious warnings about missing return statements. In fact, I'd suggest that boost::throw_exception() be tagged by such an attribute (on platform that support it). Regards, Stefan

Stefan Seefeld wrote:
Thorsten Ottosen wrote:
Hi All,
I'm about to replace all my throw Foo; statetements in the Pointer Container library with something else to support platforms without exceptions.
Is using boost::throw_exception the way to do it?
If I where on such a platform, I kinda think that I would have preferred an assertion *at the throw spot* instead of making the call stack deeper yet and then call about or something.
If it is not a throw expression it ought to be something with similar semantics, such as a function with __attribute__((__noreturn__)) (or whatever it is spelled for a particular compiler), so the compiler knows that no code past this point is ever executed. Else you may get spurious warnings about missing return statements.
is this necessary? after all, I think most function bodies would look like { if( foo() ) boost::throw_exception( ... ) ... // normal code here } Anyway, my feeling is that people that uses BOOST_NO_EXCEPTION would prefer if( foo() ) BOOST_THROW_EXCEPTION( std::exception, "MSG" ); where this expands to BOOST_ASSERT( "MSG" ) when BOOST_NO_EXCEPTION is true. Has anybody that work in an environment without exceptions got any opinions? -Thorsten

Thorsten Ottosen wrote:
Anyway, my feeling is that people that uses BOOST_NO_EXCEPTION would prefer
if( foo() ) BOOST_THROW_EXCEPTION( std::exception, "MSG" );
where this expands to BOOST_ASSERT( "MSG" ) when BOOST_NO_EXCEPTION is true.
This very much depends on foo(). In your case I suspect that foo() validates an input argument and the outer function is something similar to vector<>::at. Think about in which circumstances one would use at() - a function that "recovers gracefully" from input arguments out of range by throwing an exception - as opposed to operator[], a function that uses BOOST_ASSERT to check the input. Presumably, the client that calls at() _expects_ an exception when an out of range argument is passed, and this exception is handled somewhere; this indicates that out of range arguments to at() are expected and this code path forms an ordinary part of the program. If out of range input arguments were unexpected, one would use operator[], possibly guarded by a user-level assert. To get back to throw_exception, I guess my point is that nothing is gained by turning the throw into an assert, because people that wanted an assert would use the asserting function, not the throwing function. And of course in a situation where throw_exception is used to throw bad_alloc, an assertion makes even less sense, because there are no "logic errors" involved, and presenting the effects of a failed assertion to the end user would serve little purpose; the program could do nothing to defend itself from the out of memory situation.

Thorsten Ottosen wrote:
Anyway, my feeling is that people that uses BOOST_NO_EXCEPTION would prefer
if( foo() ) BOOST_THROW_EXCEPTION( std::exception, "MSG" );
where this expands to BOOST_ASSERT( "MSG" ) when BOOST_NO_EXCEPTION is true.
This very much depends on foo(). In your case I suspect that foo() validates an input argument and the outer function is something similar to vector<>::at.
Think about in which circumstances one would use at() - a function
Peter Dimov wrote: that "recovers gracefully" from input arguments out of range by throwing an exception - as opposed to operator[], a function that uses BOOST_ASSERT to check the input.
Presumably, the client that calls at() _expects_ an exception when an
out of range argument is passed, and this exception is handled somewhere; this indicates that out of range arguments to at() are expected and this code path forms an ordinary part of the program.
If out of range input arguments were unexpected, one would use
operator[], possibly guarded by a user-level assert. I don't think it is that simple. I've heard people saying they would like to use numeric_cast if it did not throw, but did an assertion.
To get back to throw_exception, I guess my point is that nothing is gained by turning the throw into an assert, because people that wanted an assert would use the asserting function, not the throwing function.
if that asserting function exists. it does not exists in many cases of the Pointer Container library. I think there might also be people working on platforms with exceptions who would like to get rid of the exceptions to gain a little speed. -Thorsten

Thorsten Ottosen <tottosen@dezide.com> writes:
I've heard people saying they would like to use numeric_cast if it did not throw, but did an assertion.
I think it would be a good idea to have that option. However, I don't think the global throw_exception hook is the way to get there. You want per-conversion control, not global state setting. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Thorsten Ottosen wrote:
is this necessary? after all, I think most function bodies would look like
{ if( foo() ) boost::throw_exception( ... ) ... // normal code here }
Consider this: int process(int d) { switch (d) { case 0: return process_0(); default: THROW("unexpected argument"); } } As long as THROW maps to 'throw' all is fine, but for anything else the compiler might find that you fall through the switch block and thus issues a 'missing return statement' warning/error. Regards, Stefan
participants (4)
-
David Abrahams
-
Peter Dimov
-
Stefan Seefeld
-
Thorsten Ottosen