8

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";
}
  • So why was the const throw() used in the what() virtual function? What difference it makes?

Thanks to all.

file2cable
  • 564
  • 6
  • 15
  • 3
    "as c++ doesn't strictly enforce the concept of interface" It does for pure-virtual functions, if thats what you meant. – tkausl Sep 02 '17 at 07:32
  • 1
    That throw() you omitted is a 'exception specification' it tells the compiler that the function does not throw any exceptions, the 'what()' function i.e. Not to say it enforces this. Read up on exception specifications for clarity. – Samer Tufail Sep 02 '17 at 07:42
  • 1
    Very interesting question. It's not the same question but I think [this one is helpful](https://stackoverflow.com/questions/5230463/what-does-this-function-declaration-mean-in-c) – tuket Sep 02 '17 at 07:46
  • Thank you @SamerTufail. I have a doubt where it says `the function does not throw any exceptions`. If I add modify the custom exception class as `virtual const char* what() const throw() { char *pMemory = new char[999999999999999];`, it will throw a `std::bad_alloc` exception, so what difference it makes by adding `throw()` ? – file2cable Sep 02 '17 at 08:07
  • 1
    @file2cable its a hint or a promise to the compiler that it wont throw not to say it wont. If it does throw the compiler will cause it to cause unexpected. Now either from you can return via throwing or rethrowing something or let it reach terminate() where the program will eventually terminate. – Samer Tufail Sep 02 '17 at 08:16
  • 1
    @file2cable herb sutter explains it best: http://www.gotw.ca/publications/mill22.htm – Samer Tufail Sep 02 '17 at 08:20

2 Answers2

4

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 [...]".

King Thrushbeard
  • 869
  • 10
  • 16
  • Thank you @king-thrushbeard. I have a doubt with the last part which says `guarantees not to throw an exception`. If I add modify the custom exception class as `virtual const char* what() const throw() { char *pMemory = new char[999999999999999];`, it will throw a `std::bad_alloc` exception, so on what meaning is is mentioned that it is guaranteed not to throw an exception? – file2cable Sep 02 '17 at 08:05
  • 1
    @file2cable See the link to cppreference I put in my answer: It has an example of this near the middle of the page: In summary, the exception will be thrown and results in calling `std::terminate`, aborting your program (if you did not specify a different terminate handler). – King Thrushbeard Sep 02 '17 at 08:38
4

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.

Artemy Vysotsky
  • 2,694
  • 11
  • 20