I am beginner in c++, and hence apologies for this silly question. I am posting it here because I cannot find a similar answer on stackoverflow.
I was progressing through exceptions in C++ and as I was doing some hands on with custom exceptions, I have this code
class MyException: public std::exception{
public:
virtual const char* what() const throw() {
return "something bad happened";
}
};
// class that throws above exception
class canGoWrong {
public:
canGoWrong(){
throw MyException();
}
};
The above code was shown by the teacher. The constructor just implemented a virtual function defined in the base class exception
. I got till there.
Now when I was trying a different version to practice, I tried to use a custom function instead of re-defining the virtual (as c++ doesn't strictly enforce the concept of interface, please correct me if I am wrong here.)
I wrote it as
class my_custom_shit_exception: public std::exception {
public:
const char* show() { // I omitted the const throw() here
return "This is an error encountered\n";
}
};
class myclass {
public:
myclass() {
throw my_custom_shit_exception();
}
};
To summarise, I didn't find a difference in behaviour in both ways
public:
const char* show() {
return "This is an error encountered\n";
}
virtual const char* what() const throw() {
return "something bad happened";
}
const throw()
used in the what()
virtual function? What difference it makes?Thanks to all.
Custom exceptions provide relevant information about an error to the exception handling mechanism. They can be generated by creating a new class containing the attributes needed and throwing an instance of such a class, or by inheriting from std::exception and overriding the what() function.
When an exception is thrown using the throw keyword, the flow of execution of the program is stopped and the control is transferred to the nearest enclosing try-catch block that matches the type of exception thrown. If no such match is found, the default exception handler terminates the program.
5.1 Understanding Exception HandlingIf the detecting function cannot deal with the anomaly, it "throws" an exception. A function that "handles" that kind of exception catches it. In C++, when an exception is thrown, it cannot be ignored--there must be some kind of notification or termination of the program.
A C++ exception is a response to an exceptional circumstance that arises while a program is running, such as an attempt to divide by zero. Exceptions provide a way to transfer control from one part of a program to another. C++ exception handling is built upon three keywords: try, catch, and throw.
The function signature
class std::exception {
//...
public:
virtual const char* what() const throw();
//...
};
can be read as: what
is a virtual member function of std::exception
which returns a pointer to a constant character (array) and which does not modify members of that object (hence the 2nd const
) and which guarantees not to throw an exception in its code.
Beware that the exception-specification is nowadays deprecated: Instead, since C++11 there is the noexcept
specifier to declare functions that "guarantee" not to throw exceptions. Additionally, since C++17 the throw()
has become a synonym for noexcept(true)
, but with a slightly different behaviour.
For more details, refer to this description of noexcept
.
There it also says: "Note that a noexcept specification on a function is not a compile-time check; it is merely a method for a programmer to inform the compiler whether or not a function should throw exceptions. The compiler can use this information to enable certain optimizations on non-throwing functions [...]".
I wanted to show some quotes from Scott Meyers
"Effective C++" Third Edition
int doSomething() throw(); // note empty exception spec.
This doesn’t say that doSomething will never throw an exception; it says that if doSomething throws an exception, it’s a serious error, and the unexpected function should be called. †
For information on the unexpected function, consult your favorite search engine or comprehensive C++ text. (You’ll probably have better luck searching for set_unexpected, the function that specifies the unexpected function.)
And from the "Effective Modern C++"
In C++11, unconditional noexcept is for functions that guarantee they won’t emit exceptions.
If, at runtime, an exception leaves f, f’s exception specification is violated. With the C++98 exception specification, the call stack is unwound to f’s caller, and, after some actions not relevant here, program execution is terminated. With the C++11 exception specification, runtime behavior is slightly different: the stack is only possibly unwound before program execution is terminated. The difference between unwinding the call stack and possibly unwinding it has a surprisingly large impact on code generation. In a noexcept function, optimizers need not keep the runtime stack in an unwindable state if an exception would propagate out of the function, nor must they ensure that objects in a noexcept function are destroyed in the inverse order of construction should an exception leave the function. Functions with “throw()” exception specifications lack such optimization flexibility, as do functions with no exception specification at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With