58

I am learning C++ and I am experiencing when I try and create my own exception and throw them on Linux.

I've created a small test project to test my implementation and below is my exception class header file.

class TestClass : public std::runtime_error
{
public:
    TestClass(char const* const message) throw();
    virtual char const* what() const throw();
};

The source file for the exception class is

using namespace std;

TestClass::TestClass(char const* const message) throw()
    : std::runtime_error(message)
{

}

char const * TestClass::what() const throw()
{
    return exception::what();
}

In my main app, I am calling a function which throws my exception and catches it in a try/catch as follows:

void runAFunctionAndthrow();

/*
 * 
 */
int main(int argc, char** argv) {
    try
    {
        cout << "About to call function" << endl;
        runAFunctionAndthrow();
    }
    catch (TestClass ex)
    {
        cout << "Exception Caught: " << ex.what() << endl;
    }

    return 0;
}

void runAFunctionAndthrow()
{
    cout << "going to run now. oh dear I need to throw an exception" << endl;

    stringstream logstream;
    logstream << "This is my exception error. :(";
    throw TestClass(logstream.str().c_str());
}

When I run I'm expecting to get the following output:

About to call function

Going to run now. oh dear I need to throw an exception

Exception Caught: This is my exception error. :(

Instead what I am getting is

About to call function

going to run now. oh dear I need to throw an exception

Exception Caught: std::exception

Notice the last line it says std::exception instead of my actual exception message "This is my exception error".

Why is this, it works OK on Windows but on Linux it does this.

From what I've seen on various posts what I've done is correct so what am I missing.

1
  • 4
    In what() you probably meant return runtime_error::what(); - which would amount to omit the reimplementation altogether (the base class behavior here is already good for you). Commented Jan 19, 2017 at 23:26

5 Answers 5

43

Your what() returns:

 return exception::what();

The return value from std::exception::what() is specified as follows:

Pointer to a null-terminated string with explanatory information.

That's it. Nothing more, nothing else. The text you're showing certainly qualifies as an "explanatory information". And this is the only requirement for the return value of what() (except for one other one which is not germane here).

In other words, C++ does not guarantee the exact contents of what you get with what(). what() you see is what() you get, as the saying goes.

If you want your exception to describe itself, in some way, it's up to you to implement that, as part of your what().

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

2 Comments

Given that TestClass inherits std::runtime_error it could just avoid reimplementing what() - std::runtime_error::what() already returns the message passed to its constructor.
@MatteoItalia I just noticed that and gave it a try before your comment from your explanation and it does what I was expecting now. Thanks for your help
33

You need your own implementation of what() method or use std::runtime_error::what() as written in comments

Say:

class TestClass : public std::runtime_error
{
    std::string what_message;
public:
    const char* what() const override
    {
        return what_message.c_str();
    }
};

Also, better use noexcept instead of throw() and only after you read about them - link.

And in your try-catch:

catch (const TestClass& myException)

Instead of catch(TestClass myException) - otherwise you do an implicit copy which can potentially result in an exception throw. It also breaks the polymorphism: if you want to catch pure virtual interface implementation instance, you would need to use a reference.

1 Comment

Add #include <exception>
2

You need a way to specify a custom error message to std::exception which afaik is not allowed. See this for a possible solution.

Comments

1

First of most of the info about the answer had been given by Sam Varshavchik But I want to add one thing When throwing and catching A good rule is

"Throw by value catch by reference "

So your throw was fine as:

void runAFunctionAndthrow()
{
    cout << "going to run now. oh dear I need to throw an exception"  << endl;
    stringstream logstream;
    logstream << "This is my exception error. :(";
    throw **TestClass(logstream.str().c_str())**;
}

used an implicit conversion to TestClass and then it got passed by value.

the Key point in that rule is to minimize memory allocating handling between different stack frames

your catch on the other hand dosen't follow the rule (since you catch by value):

catch (TestClass ex)
{
    cout << "Exception Caught: " << ex.what() << endl;
}

the catch should be (const TestClass& ex)

the key point in this rule is implicit conversion between base class and derived class.

Comments

1

The most succinct way to create a custom exception since C++11 is using the parent constructor of std::runtime_error:

struct my_exception: std::runtime_error {
    using std::runtime_error::runtime_error;
}

This will inherit all std::runtime_error constructors which covers the majority of exception-handling needs.

2 Comments

Is it safe to "private" inherit from std::runtime_error?
struct default is public not only for members but for inheritance too.

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.