8
namespace QuantLib {

    //! Base error class
    class Error : public std::exception {
      public:
        /*! The explicit use of this constructor is not advised.
            Use the QL_FAIL macro instead.
        */
        Error(const std::string& file,
              long line,
              const std::string& functionName,
              const std::string& message = "");
        /*! the automatically generated destructor would
            not have the throw specifier.
        */
        ~Error() throw() {}
        //! returns the error message.
        const char* what() const throw ();
      private:
        boost::shared_ptr<std::string> message_;
    };

}

As you see through the comment, the destructor of class Error explicitly provides an empty implementation with no-throw specifier.

Question: Is this necessary? Or is this a good practice comparing to let the compiler generate a implicit destructor?

iammilind
  • 68,093
  • 33
  • 169
  • 336
q0987
  • 34,938
  • 69
  • 242
  • 387
  • I had to add a no-throw destructor to my exception class that was derived from std::exception to eliminate a warning or error that gcc emitted when I had not provided one. It didn't like that the derived class didn't have the same no-throw spec as the base class. – Anon Mail May 25 '12 at 14:46
  • 1
    *If* you decide to do this, I'd use `noexcept` instead of `throw()`, if possible. Dynamic exception specifications (including `throw()`, at least as I read it) are deprecated (though if your compiler isn't up to snuff, you may not be able to do that). – Jerry Coffin May 25 '12 at 14:50

4 Answers4

9

In C++11, destructors are implicitly throw() (unless any member or base of the type has a destructor with a different exception specification) so if you are compiling in C++11 mode there is no need.

If you are in C++03, you might want to add it, but whether it will have an effect or not is very implementation defined... Now, for documentation purposes you might want to add it, but again, it is commonly assumed that destructors don't throw.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • I believe that's not accurate about C++11. – bames53 May 25 '12 at 15:04
  • In C++11, a dtor implicitly has an exception specification that's basically the union of anything thrown by anything it directly calls. It's nothrow only if it doesn't call anything that throws. [At least I believe that's the intent -- the wording is a bit messy, so it's at least arguably self-contradictory right now]. – Jerry Coffin May 25 '12 at 15:13
  • 4
    I went over this part of the standard with a coworker a few weeks ago, and the problem is that the exception specification (if none is given for the destructor) would be that of an implicitly declared destructor, which is in turn is the union of the exception specifications of all the functions that the *implicit definition* of that destructor would call, which are the destructors of all members and bases. Our understanding at the time is that `~Error() { throw 1; f(); }` would have a `noexcept(true)` exception specification even if `f` throws... – David Rodríguez - dribeas May 25 '12 at 15:46
  • 3
    ... this is an important breaking change, as unless you explicitly ask for `noexcept(false)` in this case, your program would break the contract (which is now implicitly `noexcept(true)` --again unless one of the bases or members has a different exception specification). While my wording was not 100% precise, the fact is that if you can add a `noexcept` to your destructor (i.e. it does not throw), then not writing the exception specification or not will provide the same end result: `noexcept`. – David Rodríguez - dribeas May 25 '12 at 15:50
  • 4
    ... Also note, that the actual code that runs in *this* destructor cannot affect the exception specification, as the separate compilation model implies that different translation units might only see a declaration of the destructor, so the definition of that destructor cannot be used to change the declaration. [@JerryCoffin -- added here, I forgot to add it to the first comment-answer] – David Rodríguez - dribeas May 25 '12 at 15:53
5

Destructors should always be designed to never throw exceptions. So in that sense, there's little point in declaring an empty destructor merely in order to mark it as no-throw.

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

Depends what you think throw() means.

What it actually means according to the standard is, "put extra code around every call to this function if necessary, or in the function itself, to ensure that if this function throws then the exception is caught and std::unexpected is called".

Certain compilers implemented it to mean "optimize calls to this function on the assumption that they will not throw", but (in violation of the standard) didn't implement the runtime check.

So, adding it to a destructor (which certainly shouldn't throw) out to (but in practice might not) add a runtime check that should never be triggered and therefore might help debug your code. It may or may not enable an optimization.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
3

Destructors always implicitly have exception specifications:

[class.dtor] 12.4 p3

A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4).

[except.spec] 15.4 p14

An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.

So, no, it's not necessary for you to use an exception specification.


In C++03 user defined destructors did not have an implicit exception specification, so if you do define your own destructor you can't rely on the compiler to automatically add the appropriate exception specification. But implicitly declared destructors have the same implicit exception specification as in C++11.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • @SteveJessop: The first quote (§12.4/3) is new in C++11. In C++03, the second quote is numbered §15.4/13, but (I believe) has the same wording. – Jerry Coffin May 25 '12 at 15:12