92

I've just created exception hierarchy and wanted to pass char* to constructor of one of my derived classes with a message telling what's wrong, but apparently std::exception doesn't have constructor which would allow me to do so. Yet there is a class member called what() which would suggest that some information can be passed.
How can I (can I?) pass text to derived class of a std::exception in order to pass info with my exception class, so I can say somewhere in the code:

throw My_Exception("Something bad happened.");
3
  • I know this doesn't answer your question, but you might wanna read this before you start using exceptions. There are also many questions here on stack overflow about exceptions being good or bad (the answer mostly being bad). Commented Nov 16, 2011 at 13:56
  • stackoverflow.com/q/1669514/52074 is extremely similar (almost seems like duplicate) and has more upvotes. FYI both this question and the link have the same solutions. Commented Apr 10, 2018 at 12:06
  • This one has a the better answers IMO. Both obmarg's at the top as well as Johannes's alllll the way at the bottom. Commented Jan 31, 2019 at 16:21

6 Answers 6

82

If you want to make use of the string constructor, you should inherit from std::runtime_error or std::logic_error which implements a string constructor and implements the std::exception::what method.

Then it's just a case of calling the runtime_error/logic_error constructor from your new inherited class, or if you're using c++11 you can use constructor inheritance.

Sign up to request clarification or add additional context in comments.

Comments

77

I use the following class for my exceptions and it works fine:

class Exception: public std::exception
{
public:
    /** Constructor (C strings).
     *  @param message C-style string error message.
     *                 The string contents are copied upon construction.
     *                 Hence, responsibility for deleting the char* lies
     *                 with the caller. 
     */
    explicit Exception(const char* message)
        : msg_(message) {}

    /** Constructor (C++ STL strings).
     *  @param message The error message.
     */
    explicit Exception(const std::string& message)
        : msg_(message) {}

    /** Destructor.
     * Virtual to allow for subclassing.
     */
    virtual ~Exception() noexcept {}

    /** Returns a pointer to the (constant) error description.
     *  @return A pointer to a const char*. The underlying memory
     *          is in posession of the Exception object. Callers must
     *          not attempt to free the memory.
     */
    virtual const char* what() const noexcept {
       return msg_.c_str();
    }

protected:
    /** Error message.
     */
    std::string msg_;
};

9 Comments

msg_ is a protected member of Exception; it's an instance of std::string, so it has access to it's .c_str member function (converts to c string).
what about copy constructor?
@Water This code does the same as std::runtime_error. No need to reinvent the wheel.
I don't think this is a good idea. Constructing an std::string can throw an exception, which will cause terminate to be called.
i agree with @DDrmmr's statement that you are reinventing the wheel (i.e. you are re-implementing std::runtime_error or std::logic_error).
|
16

If your goal is to create an exception so that you do not throw a generic exception (cpp:S112) you may just want to expose the exception you inherit from (C++11) with a using declaration.

Here is a minimal example for that:

#include <exception>
#include <iostream>

struct myException : std::exception
{
    using std::exception::exception;
};

int main(int, char*[])
{
    try
    {
        throw myException{ "Something Happened" };
    }
    catch (myException &e)
    {
        std::cout << e.what() << std::endl;
    }
    return{ 0 };
}

As Kilian points out in the comment section the example depends on a specific implementation of std::exception that offers more constructors than are mentioned here.

In order to avoid that you can use any of the convenience classes predefined in the header <stdexcept>. See these "Exception categories" for inspiration.

3 Comments

Having a look at en.cppreference.com/w/cpp/error/exception/exception std::exception does not have a constructor taking a string as argument. So your code is ill-formed.
@Kilian I am using implementation specific behavior which should be common and practical. Thanks for the hint I will include that in the answer.
Is it safe to "private" inherit from std::exception?
15

How about this:

class My_Exception : public std::exception
{
public:
virtual char const * what() const { return "Something bad happend."; }
};

Or, create a constructor accepting the description if you like...

3 Comments

@user472155 +1 for the good answer. By the way though, I think it worth to mention here, that the signature you provided in your example for the what function, implies only to code prior to C++11.
@Guy Avraham: do you mean that post C++11 the virtual keyword should become override, or something else?
@gg99 - Good point. I meant that since C++11, the signature of the what function turned into the following: virtual const char* what() const noexcept (note the addition of the noexcept keyword at the end). See also here: en.cppreference.com/w/cpp/error/exception/what
7

The what method is virtual, and the meaning is that you should override it to return whatever message you want to return.

Comments

2

Here is an example

 class CommunicationError: public std::exception {
  public:
   explicit CommunicationError(const char* message) : msg(message) {}
   CommunicationError(CommunicationError const&) noexcept = default;

   CommunicationError& operator=(CommunicationError const&) noexcept = default;
  ~CommunicationError() override = default;

  const char* what() const noexcept override { return msg; }
 private:
  const char* msg;
};

[1] https://web.archive.org/web/20220510100826/https://www.autosar.org/fileadmin/user_upload/standards/adaptive/17-03/AUTOSAR_RS_CPP14Guidelines.pdf

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.