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.
C++ create new exceptions by inheriting from the std::exception
You need to actually catch your exception:
try
{
throw stack_full_error("Stack is full!");
} catch(stack_full_error& ex)
{
std::cout << ex.what();
}
Is the `std::exception`, in its current form, redundant?
No, nothing stops you from doing this.
However, some code that wants to catch "any exception" will catch const std::exception&
, and if your exception type doesn't derive from std::exception
then that won't work.
Sure, we can catch ...
instead but that's, in my experience, used as a last-ditch "blunt instrument" for avoiding termination due to uncaught exceptions, and can't tell you anything about the exception itself.
Boost exceptions don't derive from std::exception
and it's really annoying.
Why not just make all the exceptions part of this standard hierarchy?
If you don't intend to ever let your exception types make get all the way to the top, then there may not be a practical problem here. But, why take the chance? You lose nothing by adding : std::runtime_error
or somesuch, and the text string that you'll pass to the base is useful information for the diagnosing programmer.
Inherit Exceptions in C++
When you catch like this:
catch (TGAException e) {
cout << e.what() << endl;
}
The compiler makes a copy of the original exception and assigns it to e. It uses the TGAException copy constructor so the exception seen inside the catch block is not an ImagetypeException, it is a TGAException. This phenomenon is called object slicing.
If you catch it this way:
catch (const TGAException & e) {
cout << e.what() << endl;
}
No copy is needed and it will work the way you expect it to.
As a general guideline: Always catch exceptions by reference, and almost always catch them by const reference.
Inherit custom exception class from both boost::exception and std::runtime_error
You need public inheritance
struct Exception : public boost::exception, public std::runtime_error
{
Exception()
: std::runtime_error("Hello World")
{}
};
int main()
{
try {
try {
throw Exception();
}
catch(const std::runtime_error&) {
std::cout << "std::runtime_error" << std::endl;
throw;
}
}
catch(const boost::exception&) {
std::cout << "boost::exceptionr" << std::endl;
}
return 0;
}
Your code will work if you replace the two virtual:
Throw in function void foo()
Dynamic exception type: boost::exception_detail::clone_impl<foo_error>
std::exception::what: foo error
[tag_foo_info*] = 100500
The boost exception library has a class deriving from your exception:
// Curiously recurring template pattern (exception.hpp:419:20)
class clone_impl: public Exception, public clone_base;
Due to virtual inheritance the most derived class is responsible to initialize the base classes (clone_impl does not)
How to inherit from std::runtime_error?
This is the correct syntax:
class err : public A, public std::runtime_error
And not:
class err : public A, public std::runtime_error("")
As you are doing above. If you want to pass an empty string to the constructor of std::runtime_error
, do it this way:
class err : public A, public std::runtime_error
{
public:
err() : std::runtime_error("") { }
// ^^^^^^^^^^^^^^^^^^^^^^^^
};
Here is a live example to show the code compiling.
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
How Does a C/C++ Compiler Find the Definitions of Prototypes in Header Files
Should Accessors Return Values or Constant References
Properties File Library for C (Or C++)
Multiplying a String by an Int in C++
What Is the Purpose of C++20 Std::Common_Reference
How to Pre-Allocate Space for a File in C/C++ on Windows
C++11 Lambdas: Member Variable Capture Gotcha
Is There Any G++ Option to Dump Class Layout and Vtables
Qapplication in Non-Main Thread
Why Does Enumwindows Return More Windows Than I Expected
What Optimization Does Move Semantics Provide If We Already Have Rvo
How to Declare Array with Auto
Best Way to Start a Thread as a Member of a C++ Class
Why Can't I Static_Cast Between Char * and Unsigned Char *
How to Create a Type List (For Variadic Templates) That Contains N-Times the Same Type