问题
The C++ Standard states the following about virtual functions that have exception specifications:
If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function (C++03 §15.4/3).
Thus, the following is ill-formed:
struct B {
virtual void f() throw() { } // allows no exceptions
};
struct D : B {
virtual void f() { } // allows all exceptions
};
(1) Does this rule apply to destructors? That is, is the following well-formed?
struct B {
virtual ~B() throw() { }
};
struct D : B {
virtual ~D() { }
};
(2) How does this rule apply to an implicitly declared destructor? That is, is the following well-formed?
struct B {
virtual ~B() throw() { }
};
struct D : B {
// ~D() implicitly declared
};
While in the general case one should never write an exception specification, this question has practical implications because the std::exception destructor is virtual and has an empty exception specification.
Since it is good practice not to allow an exception to be thrown from a destructor, let's assume for the sake of simplifying any examples that a destructor either allows all exceptions (that is, it has no exception specification) or it allows no exceptions (that is, it has an empty exception specification).
回答1:
(1) Does this rule apply to destructors?
Yes, this rule applies to destructors (there is no exception to the rule for destructors), so this example is ill-formed. In order to make it well-formed, the exception specification of ~D() must be compatible with that of ~B(), e.g.,
struct B {
virtual ~B() throw() { }
};
struct D : B {
virtual ~D() throw() { }
};
(2) How does this rule apply to implicitly declared special member function?
The C++ Standard says the following about implicitly declared special member functions:
An implicitly declared special member function shall have an exception-specification.
If
fis an implicitly declared default constructor, copy constructor, destructor, or copy assignment operator, its implicit exception-specification specifies the type-idTif and only ifTis allowed by the exception-specification of a function directly invoked byf’s implicit definition;
fshall allow all exceptions if any function it directly invokes allows all exceptions, andfshall allow no exceptions if every function it directly invokes allows no exceptions (C++03 §15.4/13).
What functions are directly invoked by an implicitly declared destructor?
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class
Xcalls
- the destructors for
X’s direct members,- the destructors for
X’s direct base classes and,- if
Xis the type of the most derived class, its destructor calls the destructors forX’s virtual base classes(C++03 §12.4/6; reformatted for easier reading).
So, an implicitly declared destructor has an exception specification that allows any exceptions allowed by any of those destructors. To consider the example from the question:
struct B {
virtual ~B() throw() { }
};
struct D : B {
// ~D() implicitly declared
};
The only destructor called by the implicitly declared ~D() is ~B(). Since ~B() allows no exceptions, ~D() allows no exceptions and it is as if it were declared virtual ~D() throw().
This exception specification is obviously compatible with ~B()'s, so this example is well-formed.
As a practical example of why this matters, consider the following:
struct my_exception : std::exception {
std::string message_;
};
~string() allows all exceptions, so the implicitly declared ~my_exception() allows all exceptions. The base class destructor, ~exception(), is virtual and allows no exceptions, so the derived class destructor is incompatible with the base class destructor and this is ill-formed.
To make this example well-formed, we can explicitly declare the destructor with an empty exception specification:
struct my_exception : std::exception {
virtual ~my_exception() throw() { }
std::string message_;
};
While the rule of thumb is never to write an exception specification, there is at least this one common case where doing so is necessary.
来源:https://stackoverflow.com/questions/3233078/how-does-an-exception-specification-affect-virtual-destructor-overriding