c++quantlib

Why does the Quantlib::Error class allocate a std::string on the heap?


In a code review recently, I had some less than kind words for something I thought awful. It turns out that it was obviously inspired by the QuantLib::Error class, which looks like this:

//! 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 = "");
    #ifdef QL_PATCH_MSVC_2013
    /*! the automatically generated destructor would
        not have the throw specifier.
    */
    ~Error() throw() override {}
    #endif
    //! returns the error message.
    const char* what() const QL_NOEXCEPT override;

  private:
    ext::shared_ptr<std::string> message_;
};

Why is the member variable ext::shared_ptr<std::string> and not just plain std::string? What reason could there be to heap-allocate the string object itself? (The QuantLib code base seems to heap-allocate just about everything just about always just about everywhere, and pulls in shared_ptr's to cope with that - a classic anti-pattern - but doing it here as well "just for consistency" strikes me as a bit much. Am I missing something?)


Solution

  • This is following the behavior of standard library exception types.

    They are supposed to be copyable without throwing exceptions, since throwing an exception during construction of an exception handler parameter would cause a call to std::terminate (and possibly in some other situations requiring a copy of the exception as well).

    If std::string was used directly, copying the exception could cause for example a std::bad_alloc to be thrown. Using a reference-counted pointer instead avoids that.