0

Could anyone explain to me this definition of standard exception in C++:

virtual const char* what() const throw();

What does const throw() mean at the end?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Bober02
  • 15,034
  • 31
  • 92
  • 178
  • 4
    Why so angry? If you get upset every time you don't know some part of C++, you'll have a heart attack in no time! Also note that exception specifiers are now deprecated, so with luck you'll see fewer and fewer of those. – Kerrek SB Dec 20 '11 at 14:03

3 Answers3

9

These are two separate, unrelated, things.

The const means that the member function won't modify any (non-mutable) member variables; this in turn means that it can be called on const objects. e.g.:

class Foo {
public:
    void a() const {
        x = 5;  // Compiler error!
    }

    void b() {
        x = 5;  // This is fine
    }

private:
    int x;
};

int main() {
    Foo       p;
    const Foo q;

    p.a();   // This is fine
    p.b();   // This is fine
    q.a();   // This is fine
    q.b();   // Compiler error!
}

The throw() is an exception specifier. It declares that this function will not throw an exception. See e.g. Should I use an exception specifier in C++? for a discussion.

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
6

The const means that the function will not change any members of the class it is embedded in, throw() is an exception specification; the function promises not to throw an exception.

Note that since C++11 the exception specification throw is deprecated because of several reasons: exception lists were too hard to maintain while throw(...) was to non-expressive, so that throw() was basically the only specification used anyway, and these specification were dynamically checked at runtime, producing a large overhead and thus slowing down your application.

Now, you can safely replace throw() with noexcept(true), or just noexcept. There will be no checks whether such a method actually throws an exception - it's a guarantee you give to the compiler, not vice versa. If an exception is thrown, std::terminate is called.

nikolas
  • 8,707
  • 9
  • 50
  • 70
2

These are separate issues.


Regarding const

From the standard (if too long, only read the bold parts):

Nonstatic member functions

[...] A non-static member function may be declared const, volatile, or const volatile. These cv-qualifiers affect the type of the this pointer (9.3.2). They also affect the function type (8.3.5) of the member function; a member function declared const is a const member function, a member function declared volatile is a volatile member function and a member function declared const volatile is a const volatile member function. [...]

The this pointer

[...] In a const member function, the object for which the function is called is accessed through a const access path; therefore, a const member function shall not modify the object and its non-static data members. [...]

Storage class specifiers

[...] The mutable specifier on a class data member nullifies a const specifier applied to the containing class object and permits modification of the mutable class member even though the rest of the object is const (7.1.6.1).

Summary: A member function qualified with const is not allowed to change any member that is not declared mutable. The reason for mutable is that even if an object is const, mechanism like caching can be done; it is good practice that the observable behavior of an object does not change by calling const member function.


Regarding throw()

Exception specifications [expect.spec]

A function declaration lists exceptions that its function might directly or indirectly throw by using an exception-specification as a suffix of its declarator.

More specifically, it is a dynamic-exception-specification, and a

[...] function is said to allow an exception of type E if its dynamic-exception-specification contains a type T for which a handler of type T would be a match (15.3) for an exception of type E.

In other words, the types within ( and ) are the exceptions that this function might throw. However, it is common practice to not use non-empty dynamic exception specifications for some good reasons.

Using throw(), i.e. an empty exception list, in pre-C++11 was accepted practice to annotate functions that never throw. However, as of C++11, the current standard, one should use noexcept instead.

Also, as of C++11,

[ Note: The use of dynamic-exception-specifications is deprecated (see Annex D). —end note ]

so use noexcept instead.

Community
  • 1
  • 1
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130