0

When you throw and unhandled std::runtime_error, the terminal automatically prints the result of what() making debugging a lot easier. Example:

#include <iostream>

int main()
{
    throw std::runtime_error("This is an error message.\n");
}

Console output:

terminate called after throwing an instance of 'std::runtime_error'
what():  This is an error message.

Custom exception classes derived by this class show the same behaviour, exception classes made from scratch don't do that by default.

But the exception class I want to create must not be derived from std::runtime_error.. And for debugging purposes, what() should still be printed after the program crashs - but I can't figure out how to do that no matter what! Can someone help me please?

At the moment, it looks like this:

#include <iostream>

struct Custom_Exception
{
    std::string Msg;

    Custom_Exception(std::string Error_Msg) noexcept
    {
        Msg=Error_Msg;
    }

    std::string what() noexcept
    {
        return Msg;
    }
};

int main()
{
    throw Custom_Exception("This is an error message.\n");
}

Console output:

terminate called after throwing an instance of 'Custom_Exception'

No what(): in the error message... Putting a std::cout<<Msg; into the destructor doesn't help either.

Please help me with your suggestions! Thank you.

Thynome
  • 71
  • 7
  • 4
    "But the exception class I want to create must not be derived from std::runtime_error." - Why not? –  Feb 27 '17 at 18:29
  • 2
    Catch your exceptions in main and do what you want with them. I wouldn't rely on the runtime to do this for you. – Anon Mail Feb 27 '17 at 18:29
  • @NeilButterworth It forces me to use certain data types or to convert them every time, it prevents me from creating a generic exception class which I want to use for my own projects, I want to know how to add this feature for the sake of curiosity. I just don't like it that way. Otherwise I could just use std::runtime_error itself... But I want by custom exception class because it can certain things std::runtime_error can't. – Thynome Feb 27 '17 at 18:43
  • 2
    @Thynome _"But I want by custom exception class because it can certain things std::runtime_error can't."_ Could you elaborate about this please? – πάντα ῥεῖ Feb 27 '17 at 18:47
  • I do not recommend a generic exception class. – knivil Feb 27 '17 at 18:49
  • `what()` is virtual. You can (and should) derive custom exceptions from `std::runtime_error` (or any other appropriate [`std::exception`-based class](http://en.cppreference.com/w/cpp/error/exception)) and override `what()` to say whatever you want. The only thing you are limited to is returning a `char*`, but you can format that using whatever data types you want. So derive a custom exception where you pass the desired data types to its constructor, and then have the constructor format the error message into a `std::string` as needed, and let `what()` return that message. – Remy Lebeau Feb 27 '17 at 19:00
  • @Thynome what you call tedious I call standard practice. – Anon Mail Feb 27 '17 at 21:55

2 Answers2

4

The minimum exception interface to use what() with the std::terminate_handler is std::exception:

struct Custom_Exception : public std::exception {
    std::string Msg;
public:
    Custom_Exception(std::string Error_Msg) noexcept : Msg(Error_Msg) {
    }

    const char* what() const { return Msg.c_str(); }
};

Another option without inheriting from the std::exception interface is to catch your custom exceptions in main()

int main()
{
    try {
        throw Custom_Exception("This is an error message.\n");
    }
    catch(const Custom_Exception& ce) {
        std::cerr << ce.what() << std::endl;
    }
}

or override and set the std::terminate_handler with your own handler.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Can you explain how to properly override `std::terminate_handler` and how I can integrate it into my exception class please? – Thynome Feb 27 '17 at 18:58
  • @Thynome I'm not finally sure if a `std::terminate_handler` override function may rethrow and catch like `try { throw; } catch(const Custom_Exception& ce) { /* ... */ }`. – πάντα ῥεῖ Feb 27 '17 at 19:11
  • You can. [except.handle]/7 says that *an implicit handler is considered active when std::terminate()[...] is entered due to a throw*, so you can safely rethrow exception from there. – Revolver_Ocelot Feb 27 '17 at 19:28
0

You should derive your exception from std::exception which offers a virtual destructor and the virtual what() method. If you override the destructor you should be able to print your message.

#include <iostream>
#include <exception>

class Custom_Exception : std::exception
{
    char const* Msg;

    Custom_Exception(char const* Error_Msg) noexcept
    {
        Msg=Error_Msg;
    }

    Custom_Exception(Custom_Exception const& other)
    {
        Msg = other.Msg;
    }

    Custom_Exception& operator=(Custom_Exception const& other)
    {
        Msg = other.Msg;
        return *this;
    }

    virtual ~Custom_Exception()
    {
    }

    virtual char const* what() const noexcept
    {
        return Msg;
    }
};

int main()
{
    try 
    {
      throw Custom_Exception("This is an error message.\n");
    }
    catch (Custom_Exception& ex)
    {
      std::cout << "what(): " << ex.what();
    }
}
Frank Schmid
  • 311
  • 1
  • 6
  • Won't this print the error message even if the exception is never thrown? And also even if it's caught? – David Schwartz Feb 27 '17 at 18:50
  • Oh, yes. Whenever the exception is destructed. So πάντα ῥεῖ's answer with the outer catch might work. – Frank Schmid Feb 27 '17 at 18:53
  • It is not the destructor's responsibility to output the error message. That is why `what()` exists, to return the error message when it is needed. – Remy Lebeau Feb 27 '17 at 19:03