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
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
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