
Disabling try/catch through preprocessor when compiling without exception support was suggested e.g by Robert Ramey in: http://aspn.activestate.com/ASPN/Mail/Message/boost/1799735 Right now there are 3 libraries near review, each using their own set of similar macros: - circular_buffer - indexed_set - serialization The reasons to use macros instead of RAII is convenience and performance. Some compilers (BCB) do not allow try/catch with exceptions disabled so some solution is needed. It would be better to have and use standardized macros in Boost. Example: macros used in indexed_set: #if !defined(BOOST_NO_EXCEPTIONS) # define BOOST_INDEXED_SET_TRY try # define BOOST_INDEXED_SET_CATCH(x) catch(x) # define BOOST_INDEXED_SET_RETHROW throw #else # define BOOST_INDEXED_SET_TRY # define BOOST_INDEXED_SET_CATCH(x) if(0) # define BOOST_INDEXED_SET_RETHROW #endif Compiles w/o warnings on VC6+, BCB gives unreachable code warning (but I'll try to find workaround). /Pavel

Right now there are 3 libraries near review, each using their own set of similar macros: - circular_buffer - indexed_set - serialization
The reasons to use macros instead of RAII is convenience and performance.
Some compilers (BCB) do not allow try/catch with exceptions disabled so some solution is needed.
It would be better to have and use standardized macros in Boost.
Example: macros used in indexed_set:
#if !defined(BOOST_NO_EXCEPTIONS) # define BOOST_INDEXED_SET_TRY try # define BOOST_INDEXED_SET_CATCH(x) catch(x) # define BOOST_INDEXED_SET_RETHROW throw #else # define BOOST_INDEXED_SET_TRY # define BOOST_INDEXED_SET_CATCH(x) if(0) # define BOOST_INDEXED_SET_RETHROW #endif
Compiles w/o warnings on VC6+, BCB gives unreachable code warning (but I'll try to find workaround).
I doubt you'll find a satisfactory one, there are pragmas that can disable those warnings, but that introduces even more code than the traditional: #ifndef BOOST_NO_EXCEPTIONS catch(x) { } #endif I suggest we review these when the first of these lib's comes up for review, anyone else want to comment? John.

"John Maddock" <john@johnmaddock.co.uk> wrote [BOOST_TRY like macros]
BCB gives unreachable code warning (but I'll try to find workaround).
I doubt you'll find a satisfactory one, there are pragmas that can disable those warnings, but that introduces even more code than the traditional:
For BCB this works without warning: if (!"") { ... }
I suggest we review these when the first of these lib's comes up for review, anyone else want to comment?
First library to review is circular_buffer and this one uses less generic macros: #if !defined(BOOST_NO_EXCEPTIONS) #define BOOST_CB_TRY try { #define BOOST_CB_UNWIND(action) } catch(...) { action; throw; } #else #define BOOST_CB_TRY #define BOOST_CB_UNWIND(action) #endif ------------------------------- I would suggest to add: #if !defined(BOOST_NO_EXCEPTIONS) # define BOOST_TRY try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw #else # define BOOST_TRY# # define BOOST_CATCH(x) if(0) # define BOOST_RETHROW #endif /Pavel

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote ... clicked wrong combination of keys and didn't finish previous email ... This snippet works on all systems I use (VC, Intel, BCB, Comeau-online) w/o warnings: #if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw #else # define BOOST_TRY # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_CATCH(x) if (!"") # else # define BOOST_CATCH(x) if(0) # endif # define BOOST_RETHROW #endif /Pavel

On 2/27/04 4:48 PM, "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote: [SNIP]
# define BOOST_INDEXED_SET_CATCH(x) if(0) [TRUNCATE]
You might want to use: #define BOOST_INDEXED_SET_CATCH(x) if(true) ; else instead. This way, any dangling "else" in the outside code doesn't get attached to your macro by mistake. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote
You might want to use:
#define BOOST_INDEXED_SET_CATCH(x) if(true) ; else
instead. This way, any dangling "else" in the outside code doesn't get attached to your macro by mistake.
You found real problem in current macros! For example: if (...) BOOST_TRY { ... } BOOST_CATCH(...) { ... } else { ... } would behave differently depending on BOOST_NO_EXCEPTIONS. Here are macros resistant to this problem: #if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY if ("") # else # define BOOST_TRY if (1) # endif # define BOOST_CATCH(x) else # define BOOST_RETHROW #endif /Pavel

Le lun 01/03/2004 à 10:26, Pavel Vozenilek a écrit :
"Daryle Walker" <darylew@hotmail.com> wrote
You might want to use:
#define BOOST_INDEXED_SET_CATCH(x) if(true) ; else
instead. This way, any dangling "else" in the outside code doesn't get attached to your macro by mistake.
You found real problem in current macros! For example:
if (...) BOOST_TRY { ... } BOOST_CATCH(...) { ... } else { ... }
would behave differently depending on BOOST_NO_EXCEPTIONS.
Here are macros resistant to this problem:
#if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY if ("") # else # define BOOST_TRY if (1) # endif # define BOOST_CATCH(x) else # define BOOST_RETHROW #endif
/Pavel
With this new definition of the macros, it seems to me you can't use multiple catch (a handler sequence). But I don't see any way to define the macros such that BOOST_TRY {} BOOST_CATCH(_) {} BOOST_CATCH(_) {} works as expected. Adding a BOOST_TRY_END would solve the problem. But maybe someone can find a better solution without adding any macro. Regards, Guillaume

Guillaume Melquiond <guillaume.melquiond@ens-lyon.fr> writes: | With this new definition of the macros, it seems to me you can't use | multiple catch (a handler sequence). But I don't see any way to define | the macros such that BOOST_TRY {} BOOST_CATCH(_) {} BOOST_CATCH(_) {} | works as expected. Adding a BOOST_TRY_END would solve the problem. But | maybe someone can find a better solution without adding any macro. Would something that resulted in: if (true) { } else if (false) { } else if (false) { } work? try { } catch () { } catch () { } -- Lgb

Le lun 01/03/2004 à 12:58, Lars Gullik Bjønnes a écrit :
Guillaume Melquiond <guillaume.melquiond@ens-lyon.fr> writes:
| With this new definition of the macros, it seems to me you can't use | multiple catch (a handler sequence). But I don't see any way to define | the macros such that BOOST_TRY {} BOOST_CATCH(_) {} BOOST_CATCH(_) {} | works as expected. Adding a BOOST_TRY_END would solve the problem. But | maybe someone can find a better solution without adding any macro.
Would something that resulted in:
if (true) { } else if (false) { } else if (false) { }
No, you get the dangling-else problem back. It's why I was suggesting a BOOST_TRY_END to correctly close the "if" (for example, "else {}")
work?
try { } catch () { } catch () { }

Guillaume Melquiond <guillaume.melquiond@ens-lyon.fr> writes: | No, you get the dangling-else problem back. It's why I was suggesting a | BOOST_TRY_END to correctly close the "if" (for example, "else {}") I see. if (foo()) try { } catch (X) { } catch (Y) { } else bar(); is the problem... I do not see any other solution than another macro or requiring to but the try/catch in a block. if (foo()) { BOOST_TRY { } BOOST_CATCH(X) { } BOOST_CATCH(Y) { } } else bar(); -- Lgb

"Peter Dimov" <pdimov@mmltd.net> writes:
Pavel Vozenilek wrote:
The reasons to use macros instead of RAII is convenience and performance.
Can you elaborate please. I'm slowly coming to the conclusion that any catch that can be replaced by RAII should be.
Sad, isn't it? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Mon, 01 Mar 2004 09:30:49 -0500, David Abrahams <dave@boost-consulting.com> wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
Can you elaborate please. I'm slowly coming to the conclusion that any catch that can be replaced by RAII should be.
Sad, isn't it?
Out of curiosity, you say "sad" because there have been previous discussions with Peter and he had a different opinion? -- Genny.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Mon, 01 Mar 2004 09:30:49 -0500, David Abrahams <dave@boost-consulting.com> wrote:
"Peter Dimov" <pdimov@mmltd.net> writes:
Can you elaborate please. I'm slowly coming to the conclusion that any catch that can be replaced by RAII should be.
Sad, isn't it?
Out of curiosity, you say "sad" because there have been previous discussions with Peter and he had a different opinion?
No, because it means we have to concede an otherwise benign standard language feature is rendered bad/dangerous/useless by various operating environments: try { ... } catch(...) { //... throw; } -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote: [...]
No, because it means we have to concede an otherwise benign standard language feature is rendered bad/dangerous/useless by various operating environments: [... catch/re-throw ...]
try { pi_ = new sp_counted_base_impl<P, D>(p, d); } join_catch(...) // nothrow region { d(p); // delete p // throw; } regards, alexander.

On Tue, 09 Mar 2004 12:51:03 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Out of curiosity, you say "sad" because there have been previous discussions with Peter and he had a different opinion?
No, because it means we have to concede an otherwise benign standard language feature is rendered bad/dangerous/useless by various operating environments:
try { ... } catch(...) { //... throw; }
Well, yes, but it seemed that Peter was making a more general point ("any catch that can be replaced", not just catch(...)) -- Genny.

Gennaro Prota wrote:
On Tue, 09 Mar 2004 12:51:03 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Out of curiosity, you say "sad" because there have been previous discussions with Peter and he had a different opinion?
No, because it means we have to concede an otherwise benign standard language feature is rendered bad/dangerous/useless by various operating environments:
try { ... } catch(...) { //... throw; }
Well, yes, but it seemed that Peter was making a more general point ("any catch that can be replaced", not just catch(...))
Right, my point was that a catch+rethrow causes stack unwinding even if there is ultimately no matching handler. This may or may not be the right behavior for the particular context/platform, but in a low-level library, we don't know, so we must be as transparent as possible.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Tue, 09 Mar 2004 12:51:03 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Out of curiosity, you say "sad" because there have been previous discussions with Peter and he had a different opinion?
No, because it means we have to concede an otherwise benign standard language feature is rendered bad/dangerous/useless by various operating environments:
try { ... } catch(...) { //... throw; }
Well, yes, but it seemed that Peter was making a more general point ("any catch that can be replaced", not just catch(...))
...and what other catches can be replaced by RAII? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Wed, 10 Mar 2004 08:22:02 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Well, yes, but it seemed that Peter was making a more general point ("any catch that can be replaced", not just catch(...))
...and what other catches can be replaced by RAII?
Am I missing something? If you know that the only exceptions that will be thrown from the try block are bad_alloc or derived, isn't (broken environments apart) catch(const bad_alloc&) the same as catch(...)? Anyway, Peter was rather considering: a) whether non-C++ exceptions are mapped into C++ EH b) whether stack unwinding is enabled for non-C++ exceptions c) whether stack unwinding happens for unhandled exceptions Personally, I don't think libraries should be concerned with b) and c). At least they could cleanup their own things and then let the user do whatever he wants with the rest. No? -- Genny.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Wed, 10 Mar 2004 08:22:02 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Well, yes, but it seemed that Peter was making a more general point ("any catch that can be replaced", not just catch(...))
...and what other catches can be replaced by RAII?
Am I missing something? If you know that the only exceptions that will be thrown from the try block are bad_alloc or derived, isn't (broken environments apart) catch(const bad_alloc&) the same as catch(...)? Anyway, Peter was rather considering:
a) whether non-C++ exceptions are mapped into C++ EH b) whether stack unwinding is enabled for non-C++ exceptions c) whether stack unwinding happens for unhandled exceptions
Personally, I don't think libraries should be concerned with b) and c). At least they could cleanup their own things and then let the user do whatever he wants with the rest. No?
I think if you review this thread you'll see that there's no argument. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Thu, 11 Mar 2004 12:21:09 -0500, David Abrahams <dave@boost-consulting.com> wrote:
I think if you review this thread you'll see that there's no argument.
No argument in favor of the macros? Yes, I see that. I was just trying to understand Peter's point, and your subsequent reply about catch-all handlers being the only ones replaceable by RAII. Peter, do you have a concrete example? I can't imagine a situation where being transparent is so important. PS: I'm a nuisance, I know :) -- Genny.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Thu, 11 Mar 2004 12:21:09 -0500, David Abrahams <dave@boost-consulting.com> wrote:
I think if you review this thread you'll see that there's no argument.
No argument in favor of the macros? Yes, I see that.
That's not what I meant. I'm not arguing with you. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Gennaro Prota wrote: [...]
I can't imagine a situation where being transparent is so important.
It's rather simple. Try/rethrow prevents uncaught exceptions from terminating the process at the "original" throw point. That's not good. And, BTW, it will somewhat confuse upcoming (sooner or later) std::expected_exception<T>(). Exploiters, I mean. ;-) regards, alexander.

Peter Dimov ha escrito:
Pavel Vozenilek wrote:
The reasons to use macros instead of RAII is convenience and performance.
Can you elaborate please. I'm slowly coming to the conclusion that any catch that can be replaced by RAII should be. Including the one in shared_count. ;-)
I think I can contribute here. Earlier versions of indexed_set did extensively use scopeguards in place of try-catch blocks. When doing the performance measures, I discovered that scopeguards were introducing a non-negligible penalty --for instance, a single-indexed indexed_set was 20% slower than its equivalent std container with scopeguards, and just 10% slower with try-catch blocks (rough figures.) See http://tinyurl.com/33e4a for current performance results. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Joaquín Mª López Muñoz <joaquin@tid.es> writes:
Peter Dimov ha escrito:
Pavel Vozenilek wrote:
The reasons to use macros instead of RAII is convenience and performance.
Can you elaborate please. I'm slowly coming to the conclusion that any catch that can be replaced by RAII should be. Including the one in shared_count. ;-)
I think I can contribute here. Earlier versions of indexed_set did extensively use scopeguards in place of try-catch blocks. When doing the performance measures, I discovered that scopeguards were introducing a non-negligible penalty --for instance, a single-indexed indexed_set was 20% slower than its equivalent std container with scopeguards, and just 10% slower with try-catch blocks (rough figures.)
I believe that. It's hard for scopeguards to compete with try/catch in cases like: try { ... } catch(...) // cleanup in this case only ... throw; } // no cleanup In cases like: try { ... } catch(...) // cleanup ... throw; } // the same cleanup again getting RAII to be as efficient as try/catch generally depends on the optimizer. If the resources can fit into registers in the try/catch, the optimizer needs to be smart enough never to put them on the stack in the RAII case. Speaking generally, that's pretty unlikely, especially on systems that bind SEH and C++ exceptions together. I think Scott Meyers once told me that Microsoft engineers had told *him* that try/catch costs more than constructing an object with a nontrivial destructor. I didn't see how it was possible, and your measurements seem to confirm my suspicions.
See http://tinyurl.com/33e4a for current performance results.
Can't see much of use there, FWIW; the graphs don't show. I had to check the material out from the sandbox CVS. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams ha escrito:
See http://tinyurl.com/33e4a for current performance results.
Can't see much of use there, FWIW; the graphs don't show. I had to check the material out from the sandbox CVS.
I don't quite get how ViewCVW really works: sometimes the images do appear, others they don't (??) Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

After discussion on this topic (very helpful), I suggest to place following code into <boost/throw_exception.hpp>: #include <boost/detail/workaround.hpp> ... #if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY { try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw # define BOOST_CATCH_END } #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY { if ("") # define BOOST_CATCH(x) else if (!"") # else # define BOOST_TRY if (true) # define BOOST_CATCH else if (false) # endif # define BOOST_RETHROW # define BOOST_CATCH_END } #endif These macros are NOT intended as recomended practice for users. They exist only to avoid having similar macros in Circular Buffer, Indexed Set and Serialization each. These macros: - do not produce warnings (VC/Intel/BCB) with or w/o exceptions enabled, - work within if/else statement, - are hopefully ugly enough so users will prefere RAII in application code, - do not conflict within Boost (1.31). As they are written for "internal purpose" only they do not need to be oficially documented, IMO. /Pavel

On Fri, 5 Mar 2004 20:31:11 +0100 "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
After discussion on this topic (very helpful), I suggest to place following code into <boost/throw_exception.hpp>:
#include <boost/detail/workaround.hpp> ...
#if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY { try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw # define BOOST_CATCH_END } #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY { if ("") # define BOOST_CATCH(x) else if (!"") # else # define BOOST_TRY if (true) # define BOOST_CATCH else if (false) # endif # define BOOST_RETHROW # define BOOST_CATCH_END } #endif
These macros are NOT intended as recomended practice for users. They exist only to avoid having similar macros in Circular Buffer, Indexed Set and Serialization each.
These macros: - do not produce warnings (VC/Intel/BCB) with or w/o exceptions enabled,- work within if/else statement, - are hopefully ugly enough so users will prefere RAII in application code,- do not conflict within Boost (1.31).
I am not "portability man" but it appears you may have only tested this when both BOOST_NO_EXCEPTIONS is defined and it is for BORLAND, as the third definition of BOOST_TRY is missing the beginning scope marker.

"Jody Hagins" <jody-boost-011304@atdesk.com> wrote
I am not "portability man" but it appears you may have only tested this when both BOOST_NO_EXCEPTIONS is defined and it is for BORLAND, as the third definition of BOOST_TRY is missing the beginning scope marker.
Yes, I stand corrected. #if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY { try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw # define BOOST_CATCH_END } #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY { if ("") # define BOOST_CATCH(x) else if (!"") # else # define BOOST_TRY { if (true) # define BOOST_CATCH else if (false) # endif # define BOOST_RETHROW # define BOOST_CATCH_END } #endif /Pavel

Pavel Vozenilek wrote:
After discussion on this topic (very helpful), I suggest to place following code into <boost/throw_exception.hpp>:
#include <boost/detail/workaround.hpp> ...
#if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY { try
Can we not add it to throw_exception.hpp please? It seems that...
As they are written for "internal purpose" only they do not need to be oficially documented, IMO.
... they belong somewhere in detail/, which is the correct place for internal undocumented helpers.

"Peter Dimov" <pdimov@mmltd.net> wrote
Can we not add it to throw_exception.hpp please? It seems that...
As they are written for "internal purpose" only they do not need to be oficially documented, IMO.
... they belong somewhere in detail/, which is the correct place for internal undocumented helpers.
Why not. Maybe <boost/detail/exception_handling_helpers.hpp>? The: #if !(defined BOOST_NO_EXCEPTIONS) # define BOOST_TRY { try # define BOOST_CATCH(x) catch(x) # define BOOST_RETHROW throw # define BOOST_CATCH_END } #else # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_TRY { if ("") # define BOOST_CATCH(x) else if (!"") # else # define BOOST_TRY { if (true) # define BOOST_CATCH else if (false) # endif # define BOOST_RETHROW # define BOOST_CATCH_END } #endif from above is hopefully without typos. /Pavel

Can we not add it to throw_exception.hpp please? It seems that...
As they are written for "internal purpose" only they do not need to be oficially documented, IMO.
... they belong somewhere in detail/, which is the correct place for internal undocumented helpers.
Why not. Maybe <boost/detail/exception_handling_helpers.hpp>?
Sounds better, lets go ahead and add them if it helps with the review of these libraries. John.
participants (12)
-
Alexander Terekhov
-
Daryle Walker
-
David Abrahams
-
Gennaro Prota
-
Giovanni Bajo
-
Guillaume Melquiond
-
Joaquín Mª López Muñoz
-
Jody Hagins
-
John Maddock
-
larsbj@gullik.net
-
Pavel Vozenilek
-
Peter Dimov