[exception] virtual inheritance troubles

In xpressive, I'm trying to follow the recommended use of Boost.Exception and use virtual inheritance in my exception class, regex_error. I'm also trying to hew as closely as possible to the standard, which says that regex_error should inherit from std::runtime_error. However, this simple use of Boost.Exception does not compile: #include <string> #include <exception> #include <boost/throw_exception.hpp> #include <boost/exception/exception.hpp> struct regex_error : virtual std::runtime_error , virtual boost::exception { explicit regex_error(std::string const& what) : std::runtime_error(what) {} }; int main() { boost::throw_exception(regex_error("what")); } On VC9, I get the following:
C:\boost\org\trunk\boost/exception/exception.hpp(400) : error C2512: 'std::runtime_error::runtime_error' : no appropriate default constructor available
The trouble is that std::runtime_error does not have a default constructor, and that boost::throw_exception doesn't simply throw the exception passed to it; it throws an object of type of clone_impl<regex_error>. Because of the virtual inheritance, clone_impl needs to call std::runtime_error's directly, but it doesn't. It can't know to do that in general. What is the recommended practice here? <aside> It actually doesn't seem to be particularly useful in this case to use virtual inheritance because std::runtime_error inherits from std::exception non-virtually. In order to avoid the pitfall described here <http://tinyurl.com/yb2jpns>, it seems *ever* exception type in the hierarchy needs to use virtual inheritance, and that unfortunately is not the case for the standard exception hierarchy. </aside> -- Eric Niebler BoostPro Computing http://www.boostpro.com

In xpressive, I'm trying to follow the recommended use of Boost.Exception and use virtual inheritance in my exception class, regex_error. I'm also trying to hew as closely as possible to the standard, which says that regex_error should inherit from std::runtime_error.
Eric Niebler wrote: the standard says that regex_error doesn't not use virtual inheritance.
However, this simple use of Boost.Exception does not compile:
#include <string> #include <exception> #include <boost/throw_exception.hpp> #include <boost/exception/exception.hpp>
#include <stdexcept> is missing
struct regex_error : virtual std::runtime_error , virtual boost::exception { explicit regex_error(std::string const& what) : std::runtime_error(what) {} };
int main() { boost::throw_exception(regex_error("what")); }
On VC9, I get the following:
C:\boost\org\trunk\boost/exception/exception.hpp(400) : error C2512: 'std::runtime_error::runtime_error' : no appropriate default constructor available
The trouble is that std::runtime_error does not have a default constructor, and that boost::throw_exception doesn't simply throw the exception passed to it; it throws an object of type of clone_impl<regex_error>. Because of the virtual inheritance, clone_impl needs to call std::runtime_error's directly, but it doesn't. It can't know to do that in general.
What is the recommended practice here?
<aside> It actually doesn't seem to be particularly useful in this case to use virtual inheritance because std::runtime_error inherits from std::exception non-virtually. In order to avoid the pitfall described here <http://tinyurl.com/yb2jpns>, it seems *ever* exception type in the hierarchy needs to use virtual inheritance, and that unfortunately is not the case for the standard exception hierarchy.
gcc says basically the same this make me wonder why the standard exception hierarchy does not use virtual inheritance?
</aside>
BR, Dmitry

On Thu, Feb 25, 2010 at 9:33 PM, Eric Niebler <eric@boostpro.com> wrote:
The trouble is that std::runtime_error does not have a default constructor, and that boost::throw_exception doesn't simply throw the exception passed to it; it throws an object of type of clone_impl<regex_error>. Because of the virtual inheritance, clone_impl needs to call std::runtime_error's directly, but it doesn't. It can't know to do that in general.
I'm attaching a patch with a rather ugly workaround for the problem. I really don't like it but it is one possible solution. An alternative solution can be to derive from clone_base and implement cloning "manually". Unfortunately this would also require a modification to throw_exception to detect when a type derives from clone_base already and not inject it as a base (it does something similar for the boost::exception type itself.) I'm out of other ideas but I'm definitely interested to hear other opinions about this issue.
<aside> It actually doesn't seem to be particularly useful in this case to use virtual inheritance because std::runtime_error inherits from std::exception non-virtually. In order to avoid the pitfall described here <http://tinyurl.com/yb2jpns>, it seems *every* exception type in the hierarchy needs to use virtual inheritance, and that unfortunately is not the case for the standard exception hierarchy. </aside>
Yes, unfortunately. However, it seems like implementations should be able to detect when the type being thrown could possibly lead to ambiguities at the catch site and report a warning in this case? I wonder if any compilers do this check. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Fri, Feb 26, 2010 at 3:54 AM, Peter Dimov <pdimov@pdimov.com> wrote:
Eric Niebler wrote:
struct regex_error : virtual std::runtime_error , virtual boost::exception
There is no need to derive virtually from runtime_error. As you say below, this serves no purpose.
The purpose it serves is that someone catching std::runtime_error won't get silent errors, even though there is still a problem with std::exception. Also the problem Eric points at is more generic, there may be other exception types that are not default-constructable. I feel that we should have a recommendation for this situation anyway. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
On Fri, Feb 26, 2010 at 3:54 AM, Peter Dimov <pdimov@pdimov.com> wrote:
Eric Niebler wrote:
struct regex_error
virtual std::runtime_error , virtual boost::exception
There is no need to derive virtually from runtime_error. As you say below, this serves no purpose.
The purpose it serves is that someone catching std::runtime_error won't get silent errors, even though there is still a problem with std::exception.
I think that this can only happen if a derived class somehow ends up with two runtime_error bases; this is unlikely. Two std::exception bases, or two boost::exception bases, can occur, but the virtual inheritance from runtime_error cannot help.

On Fri, Feb 26, 2010 at 10:41 AM, Peter Dimov <pdimov@pdimov.com> wrote:
Emil Dotchevski wrote:
On Fri, Feb 26, 2010 at 3:54 AM, Peter Dimov <pdimov@pdimov.com> wrote:
Eric Niebler wrote:
struct regex_error
virtual std::runtime_error , virtual boost::exception
There is no need to derive virtually from runtime_error. As you say below, this serves no purpose.
The purpose it serves is that someone catching std::runtime_error won't get silent errors, even though there is still a problem with std::exception.
I think that this can only happen if a derived class somehow ends up with two runtime_error bases; this is unlikely.
It is less likely compared to std::exception, but it is still a possibility and I don't see why it shouldn't be avoided if possible (it isn't possible for std::exception in this case, but it is possible for std::runtime_error.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (4)
-
Dmitry Goncharov
-
Emil Dotchevski
-
Eric Niebler
-
Peter Dimov