Boardy
Boardy

Reputation: 36237

Creating custom exceptions in C++

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.

Upvotes: 56

Views: 104285

Answers (5)

Alex Veleshko
Alex Veleshko

Reputation: 1242

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.

Upvotes: 1

andrgolubev
andrgolubev

Reputation: 885

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.

Upvotes: 31

Oren Gold
Oren Gold

Reputation: 11

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.

Upvotes: 1

Furkan Fidan
Furkan Fidan

Reputation: 121

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

Upvotes: 2

Sam Varshavchik
Sam Varshavchik

Reputation: 118435

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().

Upvotes: 41

Related Questions