
Hi, I ran into a problem when trying to use BOOST_TRY/BOOST_CATCH to add no-exception support to property tree. Here's an example of the original code; try { write_ini(stream, pt, flags); } catch (ini_parser_error &e) { BOOST_PROPERTY_TREE_THROW(ini_parser_error( e.message(), filename, e.line())); } I converted this code to use the macros from core/no_exception_support.hpp *BOOST_TRY *{ write_ini(stream, pt, flags); } *BOOST_CATCH *(ini_parser_error &e) { BOOST_PROPERTY_TREE_THROW(ini_parser_error( e.message(), filename, e.line())); } *BOOST_CATCH_END* The issue is that now the exception, ini_parser_error& e, is not defined when I compile with exceptions off. I solved this by adding a local instance of ini_parser_error above the try block *ini_parser_error e("", "", 0);* BOOST_TRY { write_ini(stream, pt, flags); } BOOST_CATCH (ini_parser_error &e) { BOOST_PROPERTY_TREE_THROW(ini_parser_error( e.message(), filename, e.line())); } BOOST_CATCH_END This is a little gross, but it's not too bad and I was expecting the variable to be optimized away. But it isn't -- instantiating that exception on the stack is very clearly generating instructions on VS2015 and GCC 5.3. While this is not a huge deal, I don't like it so one way I can think to fix this is to conditionally compile out the catch block, but that defeats the purpose of the macros in the first place. BOOST_TRY { write_ini(stream, pt, flags); } BOOST_CATCH (ini_parser_error &e) { *#ifdef BOOST_NO_EXCEPTIONS* BOOST_PROPERTY_TREE_THROW(ini_parser_error( e.message(), filename, e.line())); *#endif* } BOOST_CATCH_END Then I thought maybe I can declval a fake 'e' in the else block by redefining the macros as follows; #ifndef BOOST_NO_EXCEPTIONS #define BOOST_TRY { try { #define BOOST_CATCH(type, var) } catch(type var) { #define BOOST_CATCH_END } } #else #define BOOST_TRY { if(true) { #define BOOST_CATCH(type, var) } else if(false) { type var = boost::declval<type>(); #define BOOST_CATCH_END } } #endif This is working, but is possibly undefined behaviour. Does anyone have thoughts on that? It also requires splitting up the type from the variable name. The next step to this would be to add a third parameter for some constructor args so we can just create an exception object directly. Something like: #define BOOST_CATCH(exception_type, var, args) } else if(false) { boost::decay<exception_type>::type var args; So now the original code would look like this: BOOST_TRY { write_ini(stream, pt, flags); } BOOST_CATCH (ini_parser_error&, e, ("", "", 0)) { BOOST_PROPERTY_TREE_THROW(ini_parser_error( e.message(), filename, e.line())); } BOOST_CATCH_END This is starting to look a little nasty to me so I'm wondering if anyone has any thoughts on this? Should I stop worrying about it and just use the #ifdef? The reality is that I work in an environment without exceptions and we hit these things from time to time so I'd like to fix up as many as possible. Thanks, -- chris

On 2016-02-21 23:15, Chris Glover wrote: [snip]
This is starting to look a little nasty to me so I'm wondering if anyone has any thoughts on this? Should I stop worrying about it and just use the #ifdef?
I think so, yes. I would just use an #ifdef. The problem with these macros (for me, at least) is that it's not clear what the actual error handling is supposed to be in case if exceptions are disabled. I mean, if you want the code to support the "no exceptions" case, you should design the interfaces with a different method of communicating failures, and simply removing try/catch/throw does not cut it.

On Sun, 21 Feb 2016 at 19:06 Andrey Semashev <andrey.semashev@gmail.com> wrote:
On 2016-02-21 23:15, Chris Glover wrote:
I think so, yes. I would just use an #ifdef.
The problem with these macros (for me, at least) is that it's not clear what the actual error handling is supposed to be in case if exceptions are disabled. I mean, if you want the code to support the "no exceptions" case, you should design the interfaces with a different method of communicating failures, and simply removing try/catch/throw does not cut it.
Yes, I agree with your point of view from a theoretical perspective. In reality, we don't don't need handle the exceptional case because we control all of inputs so we just need the code to compile and run the try block. I think it's fair, and most would understand, that if you're compiling with exceptions disabled then you're on your own. What I want is for code using try/catch/throw to compile fine, but call terminate when encountering a throw. Anyway, thank you for the advice, I'll give this all some thought. -- chris
participants (2)
-
Andrey Semashev
-
Chris Glover