Should I Inherit from Std::Exception

Correct way to inherit from std::exception

If you want to make use of the string constructor, you should inherit from std::runtime_error or std::logic_error which implements a string constructor and implements the std::exception::what method.

Then it's just a case of calling the runtime_error/logic_error constructor from your new inherited class, or if you're using c++11 you can use constructor inheritance.

Should I inherit from std::exception?

The main benefit is that code using your classes doesn't have to know exact type of what you throw at it, but can just catch the std::exception.

Edit: as Martin and others noted, you actually want to derive from one of the sub-classes of std::exception declared in <stdexcept> header.

C++ Exceptions and Inheritance from std::exception

When you inherit privately, you cannot convert to or otherwise access that base class outside of the class. Since you asked for something from the standard:

§11.2/4:

A base class is said to be accessible if an invented public member of the base class is accessible. If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that base class (4.10, 4.11).

Simply put, to anything outside the class it's like you never inherited from std::exception, because it's private. Ergo, it will not be able to be caught in the std::exception& clause, since no conversion exists.

Is Virtual Inheritance necessary for Exceptions?

You're probably thinking about this Boost.Exception guideline, which I'll copy here for completeness:



Using Virtual Inheritance in Exception Types

Exception types should use virtual inheritance when deriving from other exception types. This insight is due to Andrew Koenig. Using virtual inheritance prevents ambiguity problems in the exception handler:

#include <iostream>
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};

int
main()
{
try { throw your_exc3(); }
catch(std::exception const& e) {}
catch(...) { std::cout << "whoops!" << std::endl; }
}

The program above outputs "whoops!" because the conversion to std::exception is ambiguous.

The overhead introduced by virtual inheritance is always negligible in the context of exception handling. Note that virtual bases are initialized directly by the constructor of the most-derived-type (the type passed to the throw statement, in case of exceptions.) However, typically this detail is of no concern when boost::exception is used, because it enables exception types to be trivial structs with no members (there's nothing to initialize.) See Exception Types as Simple Semantic Tags.

Is it advisable to inherit from std::optional?

Is this still a bad idea? And if yes, what can go wrong?

As you already stated, inheriting from classes without virtual destructor leads to UB when destroyed from base class.

In addition, when inheriting from 3rd party library classes, you also depends of future interface.

You might be in trouble when/if std::optional adds functions with same name (especially constructors). Depending of the "conflicts", your code might no longer compile, or worst, select the wrong overload and behave not as you expect.

Note that it is not only member functions, but also apply to free functions and so ADL. So it also applies when removing methods/function/overload (unlikely for std though).

Less immediate problematic, even without conflicts, is that interface of your class change with function not necessary matching your expected interface.

Can't catch class derived from std::exception by reference to std::exception

When you inherit from a base class during the definition of a class, the default access modifier for the inheritance is private. This means that the two following definitions are equivalent:

class derived : base { /* ... */ };
class derived : private base { /* ... */ };

The language doesn't allow1 you to refer to a derived class from a private base2. As an example, the following code does not compile:

int main()
{
derived d;
base& b = d; // <== compilation error
}
error: 'base' is an inaccessible base of 'derived'
base& b = d;
^

live example on wandbox.org


This is the reason why your catch block cannot handle Exception. Change your inheritance to public...

class Exception : public std::exception

...and your original code will work.

live example on wandbox.org


1 See [dcl.init.ref] and [conv.ptr].

2 Unless you're in the scope of derived itself. See this live example on wandbox.org.



Related Topics



Leave a reply



Submit