[Exception] How do I inherit custom exception hierarchy from std::runtime_error rather than from std::exception?

Hi,
The issue that's confusing me arose from my intention of inheriting my
exception classes from std::runtime_error rather than from
std::exception. It seemed logical to me, as my exceptions are really
runtime errors; getting something meaningful via what() also seemed
like a good idea. However, this doesn't compile:
#include <iostream>
#include <stdexcept>
#include

AMDG On 11/27/2013 08:19 AM, Egor Tensin wrote:
<snip>
#include <iostream> #include <stdexcept>
#include
typedef boost::error_info
foo_info; struct foo_error : virtual boost::exception, virtual std::runtime_error { explicit foo_error(const char *const what) : std::runtime_error(what) { }
explicit foo_error(const std::string& what) : std::runtime_error(what) { } }; <snip>
It says that there's no default constructor available for std::runtime_error. How do I fix this or should I use the idiomatic approach? The interesting thing is that if I erase the "virtual" keyword, the program compiles flawlessly. I wonder what is the reason for that, e.g. why the original code doesn't work and why the new code does, what are the consequences of making boost::exception and std::runtime_error base (non-virtual) classes, etc. I'm confused as the docs clearly recommends I build exception classes hierarchy using virtual inheritance. Could somebody please give me an insight into the inner workings of the library & inheritance mechanisms?
The reason that this causes a problem is that BOOST_THROW_EXCEPTION creates a class derived from its argument's type. The constructor of a virtual base is always called from the most derived class. Since Boost.Exception doesn't know that your exception type derives from std::runtime_error, it just calls the default constructor of std::runtime_error, which doesn't exist. In Christ, Steven Watanabe

Steven,
Could you please specify, you meant the error_info_injector class
inside the Boost.Exception? I'm just trying to get this straight in my
head. Or maybe you don't know what class exactly derives from the
class passed as the parameter?
Thanks, Egor.
On Wed, Nov 27, 2013 at 10:41 PM, Steven Watanabe
AMDG
On 11/27/2013 08:19 AM, Egor Tensin wrote:
<snip>
#include <iostream> #include <stdexcept>
#include
typedef boost::error_info
foo_info; struct foo_error : virtual boost::exception, virtual std::runtime_error { explicit foo_error(const char *const what) : std::runtime_error(what) { }
explicit foo_error(const std::string& what) : std::runtime_error(what) { } }; <snip>
It says that there's no default constructor available for std::runtime_error. How do I fix this or should I use the idiomatic approach? The interesting thing is that if I erase the "virtual" keyword, the program compiles flawlessly. I wonder what is the reason for that, e.g. why the original code doesn't work and why the new code does, what are the consequences of making boost::exception and std::runtime_error base (non-virtual) classes, etc. I'm confused as the docs clearly recommends I build exception classes hierarchy using virtual inheritance. Could somebody please give me an insight into the inner workings of the library & inheritance mechanisms?
The reason that this causes a problem is that BOOST_THROW_EXCEPTION creates a class derived from its argument's type. The constructor of a virtual base is always called from the most derived class. Since Boost.Exception doesn't know that your exception type derives from std::runtime_error, it just calls the default constructor of std::runtime_error, which doesn't exist.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Thu, Nov 28, 2013 at 3:29 AM, Egor Tensin
Steven,
Could you please specify, you meant the error_info_injector class inside the Boost.Exception? I'm just trying to get this straight in my head. Or maybe you don't know what class exactly derives from the class passed as the parameter?
Allow me -- calling boost::throw_exception throws an internal type that derives from the type of the passed object. As in the example below, that internal type's constructor initializes the virtual bases of the object, but it doesn't know about the virtual bases of the object -- so they get initialized by their *default* constructor. #include <iostream> struct a { int v; a(int v): v(v) { } }; struct b: virtual a { b(): a(1) { } }; struct c: b { c(): a(2) { } }; int main() { c x; std::cout << x.v; //prints "2" return 0; } -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Oh, ok, I think I got this! Thank you very much for your help.
On Fri, Nov 29, 2013 at 3:23 AM, Emil Dotchevski
On Thu, Nov 28, 2013 at 3:29 AM, Egor Tensin
wrote: Steven,
Could you please specify, you meant the error_info_injector class inside the Boost.Exception? I'm just trying to get this straight in my head. Or maybe you don't know what class exactly derives from the class passed as the parameter?
Allow me -- calling boost::throw_exception throws an internal type that derives from the type of the passed object. As in the example below, that internal type's constructor initializes the virtual bases of the object, but it doesn't know about the virtual bases of the object -- so they get initialized by their *default* constructor.
#include <iostream> struct a { int v; a(int v): v(v) { } }; struct b: virtual a { b(): a(1) { } }; struct c: b { c(): a(2) { } }; int main() { c x; std::cout << x.v; //prints "2" return 0; }
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Wed, Nov 27, 2013 at 8:19 AM, Egor Tensin
The issue that's confusing me arose from my intention of inheriting my exception classes from std::runtime_error rather than from std::exception. It seemed logical to me, as my exceptions are really runtime errors; getting something meaningful via what() also seemed like a good idea. However, this doesn't compile:
<cut>
struct foo_error : virtual boost::exception, virtual std::runtime_error { explicit foo_error(const char *const what) : std::runtime_error(what) { }
Yes, you'd have to use non-virtual inheritance if you want to be able to pass the what parameter like this. However, I would recommend deriving virtually from std::exception and using different exception types rather than different what strings for different failures. It is usually appropriate to override what() and implement it in terms of diagnostic_information_what (see www.boost.org/doc/libs/release/libs/exception/doc/diagnostic_information_what.html.) -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Nov 27, 2013 9:52 PM, "Emil Dotchevski"
On Wed, Nov 27, 2013 at 8:19 AM, Egor Tensin
wrote:
The issue that's confusing me arose from my intention of inheriting my exception classes from std::runtime_error rather than from std::exception. It seemed logical to me, as my exceptions are really runtime errors; getting something meaningful via what() also seemed like a good idea. However, this doesn't compile:
<cut>
struct foo_error : virtual boost::exception, virtual std::runtime_error { explicit foo_error(const char *const what) : std::runtime_error(what) { }
Yes, you'd have to use non-virtual inheritance if you want to be able to pass the what parameter like this. However, I would recommend deriving virtually from std::exception and using different exception types rather than different what strings for different failures. It is usually appropriate to override what() and implement it in terms of diagnostic_information_what (see
www.boost.org/doc/libs/release/libs/exception/doc/diagnostic_information_what.html .) Your advice makes sense to me but I'm curious what semantics you write off, either explicit in the runtime_error definition or implied by library or development tool interpretation of runtime_error.
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Wed, Nov 27, 2013 at 10:39 PM, Eric Prud'hommeaux
On Nov 27, 2013 9:52 PM, "Emil Dotchevski"
wrote: On Wed, Nov 27, 2013 at 8:19 AM, Egor Tensin
wrote: The issue that's confusing me arose from my intention of inheriting my exception classes from std::runtime_error rather than from std::exception. It seemed logical to me, as my exceptions are really runtime errors; getting something meaningful via what() also seemed like a good idea. However, this doesn't compile:
<cut>
struct foo_error : virtual boost::exception, virtual std::runtime_error { explicit foo_error(const char *const what) : std::runtime_error(what) { }
Yes, you'd have to use non-virtual inheritance if you want to be able to pass the what parameter like this. However, I would recommend deriving virtually from std::exception and using different exception types rather than different what strings for different failures. It is usually appropriate to override what() and implement it in terms of diagnostic_information_what (see
www.boost.org/doc/libs/release/libs/exception/doc/diagnostic_information_what.html.)
Your advice makes sense to me but I'm curious what semantics you write off, either explicit in the runtime_error definition or implied by library or development tool interpretation of runtime_error.
I've never seen anyone catch a std::runtime_error for any other reason than to print the what() string; and std::exception is just as good for that. The other thing is, virtual inheritance is used in exception class hierarchies to enable safe use of multiple inheritance, but std::runtime_error doesn't derive virtually from std::exception. This makes std::runtime_error and virtual inheritance mutually exclusive in my book. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (4)
-
Egor Tensin
-
Emil Dotchevski
-
Eric Prud'hommeaux
-
Steven Watanabe