2

I wrote my own exception class, deriving from std::runtime_error to have Error-IDs, timestamps and inner exceptions. It seems to work, but are there any drawbacks?

The only thing I see is the deep-copy in the copy-constructor, which is not efficient, when there are many nested exceptions. But exceptions should be rare and not be nested too much, so I think it's a downside I can cope with.

#pragma once

#include <stdexcept>
#include <string>
#include <sstream>
#include <time.h>
#include <memory>


class MyException : public std::runtime_error
{
public:
    MyException(const MyException& exception)
        : std::runtime_error(exception.what()),
        exceptionId(exception.id()),
        ts(exception.timestamp()),
        innerException(NULL)
    {
        if (exception.inner() != NULL)
        {
            innerException = new MyException(*exception.inner());
        }
        else
        {
            innerException == NULL;
        }
    }

    MyException(const std::string& _Message)
        : std::runtime_error(_Message),
            exceptionId(0),
        innerException(NULL)
    {
        time(&ts);
    }

    MyException(const std::string& _Message, unsigned int id)
        : std::runtime_error(_Message),
        exceptionId(id),
        innerException(NULL)
    {
        time(&ts);
    }

    MyException(const std::string& _Message, unsigned int id, MyException* innerException)
        : std::runtime_error(_Message),
        exceptionId(id),
        innerException(new MyException(*innerException))
    {
        time(&ts);
    }

    virtual ~MyException()
    {
        delete innerException;
    }

    unsigned int id() const { return exceptionId; }
    time_t timestamp() const { return ts; }
    const MyException* inner() const { return innerException; }

private:
    unsigned int exceptionId;
    time_t ts;
    const MyException* innerException;
};

This is how I would use it:

void handleException(MyException *ex)
{
    cout << "exception " << ex->id() << " - " << ex->what() << endl;
    const MyException* innerException = ex->inner();
    int t = 1;
    while (innerException != NULL)
    {
        for (int i=0; i<t; ++i)
        {
            cout << "\t";
        }
        ++t;
        cout << "inner exception " << innerException->id() << " - " << innerException->what() << endl;
        innerException = innerException->inner();
    }
}

void throwRecursive(int temp)
{
    if (temp == 0)
    {
        throw runtime_error("std::runtime_error");
    }

    try
    {
        throwRecursive(--temp);
    }
    catch (MyException &ex)
    {
        throw MyException("MyException", (temp+1), &ex);
    }
    catch (exception &ex)
    {
        throw MyException(ex.what(), (temp+1));
    }
}

void myExceptionTest()
{
    try
    {
        throwRecursive(3);
    }
    catch (MyException &ex)
    {
        handleException(&ex);
    }
}

And the output:

exception 3 - MyException
        inner exception 2 - MyException
                inner exception 1 - std::runtime_error
Ben
  • 4,486
  • 6
  • 33
  • 48
  • 1
    It is generally expected that you will create your own exception classes so that you can specifically catch them and handle the special errors that occur in your code differently than anything the standard libraries would throw. So why not have a base exception class all your own exceptions derive from that contains common "extra" functionality like timestamps? Good idea. – Clark Oct 09 '12 at 13:41
  • @Cheers: thank you, your first answer is helping me a lot :) I have to start somewhere... – Ben Oct 09 '12 at 13:44
  • Dear commenters, I posted the same question to stackexchange (http://codereview.stackexchange.com/questions/16357/is-there-anything-wrong-with-miy-self-implemented-c-exception-class): I'd be happy, if you would answer there. – Ben Oct 09 '12 at 14:12

0 Answers0