23

I want to custom an Exception class, here's the code:

class TestException : std::exception{
  public:
  const char *what() const override {
    return "TestException";
  }
};

I used Clion and the IDE give me a warning on the function what():exception specification of overriding function is more lax than base version

But if I build the code with gcc, there's no warning came out. I used c++ 14, gcc 6.5.0

Can anybody help to explain what does the warning mean and can I just ignore it?

  • 6
    Probably the lack of `noexcept` ? – Sid S Dec 18 '18 at 09:30
  • As a side note, I recommend inheriting from `std::logic_error` or `std::runtime_error` instead, it is more specific and it also allows you to set the error message right on construction. The base class takes care of `what()`. Lazy formatting is usually a bad idea anyway for (e.g.) the reason given in my comment to P.W's answer. – Arne Vogel Dec 19 '18 at 12:58

3 Answers3

19

what from std::exception is a virtual function and a virtual function in a derived class cannot have a laxer exception specification than the function it overrides in the base class.

This is mentioned in the section on "Exception specifications" in the standard.

18.4 Exception specifications [except.spec]
...
4. If a virtual function has a non-throwing exception specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall have a non-throwing exception specification, unless the overriding function is defined as deleted.

And the example given (which is somewhat similar to the code in the question) illustrates this as well.

struct B 
{ 
  virtual void f() noexcept; 
  virtual void g(); 
  virtual void h() noexcept = delete; 
};
struct D: B 
{ 
  void f(); // ill-formed 
  void g() noexcept; // OK 
  void h() = delete; // OK 
}; 

The declaration of D::f is ill-formed because it has a potentially-throwing exception specification, whereas B::f has a non-throwing exception specification.

The solution is to change your code like:

class TestException : std::exception{
  public:
  const char *what() const noexcept override {
    return "TestException";
  }
};

See compilation here.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • What you don't mention is the rather obvious reason why `what()` is `noexcept` – it would be rather annoying to have an exception raised while trying to figure out what some other exception was. This strongly discourages lazy formatting of exception messages, and is also likely why `what()` doesn't return a `std::string` (copying that could throw). – Arne Vogel Dec 19 '18 at 12:55
6

what member function of std::exception is declared as noexcept since C++11. You should therefore make your overridden what noexcept as well. (Actually, this is what the error message says.)

Note that the noexcept keyword must come before the override keyword (see, e.g., The order of override and noexcept in the standard for details).

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
0

The warning you are facing is related to the fact that you are using C++14, if you would compile with C++17 this becomes an error. Hence I would not recommend ignoring it.

Whats going on?

std::exception defines the method what as: virtual const char* what() const noexcept;. You inherit from this method and you re-implement it without specifying noexcept. By result, you are telling that your implementation can throw exceptions, while the base method indicates this should never throw. (And callers will assume so)

This was fixed in C++17, which made noexcept part of the type system, and requires you to fix this code:

const char *what() const noexcept override
JVApen
  • 11,008
  • 5
  • 31
  • 67