Sign up ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I've looked at boost::exception and realized it is too advanced for my project, as my colleagues mostly have legacy C background. I do not need arbitrarily complex information in exception, just some error messages and trace info that can be written to process log.

Someone on Stack Overflow wrote such code as an example, but his solution can throw while trying to insert additional exception info (looks dangerous to me, correct me if I am wrong).

I tried to avoid using anything that can throw (vector of strings) inside the exception object. See: usage example.

Your feedback in term of correctness, ease of use, and required additional functionality is welcome.

const unsigned int long_enough = 512;
class my_exception : public exception {
    std::array<char, long_enough> err;
    std::array<char, long_enough>::iterator insertion_point;
public:
    template <typename Iter>
    void append(Iter first, Iter last) noexcept {
        //Remember null terminator!
        auto space_left = std::distance(insertion_point, err.end());
        if (std::distance(first, last)>=space_left){
            last = first + (space_left - 1);
        }
        insertion_point = copy(first, last, insertion_point);
    }
    void append(const char msg[]) noexcept {
        append(msg, msg+strlen(msg));
    }
    my_exception(const char msg[]) noexcept {
        insertion_point = err.begin();
        append(msg, msg+strlen(msg));
    }
    virtual const char* what() const noexcept override{
        return err.data();
    }
};
share|improve this question

1 Answer 1

A note on the the link you posted; the OP was asking a hypothetical question in regards to what happens ('under the hood') to the call stack/exception/etc. if the exception that is caught is of a reference type (i.e. catch (std::exception& e) vs catch (const std::exception& e)). As was answered there, yes it is not a good idea to modify the exception within a catch (though completely legal code, still not advised).

Per your code, there are a couple of things worth noting: Changing your err type from a std::array<char, long_enough> to a std::string would simplify all of your code, also, don't pass const char[] into functions, pass a pointer instead const char*, passing a char[] could cause stack issues, also, if you're working with C++, unless you have a specific need to use a char[] use a std::string; note that if you're intent WAS to pass in a reference to a char[], it's recommended you pass a const size template<int N> someFn(const char (&x)[N]). Lastly, while having an append function to add aditional information into your exception object could be useful, it's usually better to derive a specific exception from your base exception with specific information in it (or otherwise just put the needed information in your throw exception...). Here's you're exception class with the err variable being a std::string

class my_exception : virtual public std::exception {
private:
    std::string err;
public:
    void append(std::string::iterator first, std::string::iterator last) {
        err.append(first, last);
    }
    void append(const char* msg) {
        err.append(msg);
    }
    my_exception(const char* msg) noexcept : err(msg) {}
    virtual const char* what() const throw() {
        return err.c_str();
    }
};

Use it like such:

try {
    throw my_exception("here's a simple message");
} catch (std::exception e) {
     e.append("...added some text");
     std::cout << "error: " << e.what() << std::endl;
     // or printf("error: %s\n", e.what()) for your C friends
}

As a side note (and for reference), here is the exception code from part of an open source framework I'm working on (just in a single header file exception.hpp):

#include <iostream>
#include <exception>
#include <string>

namespace your_namespace {
    class exception : virtual public std::exception {
        public:
            exception() throw() : m_what("general exception") {}
            exception(const char *reason) throw() : m_what(reason) {}
            exception(const std::string& reason) throw() : m_what(reason) {}
            virtual ~exception() throw() {}
            virtual const char* what() const throw() { return m_what.c_str(); }
            virtual void seterr(const char *err) { this->m_what = std::string(err); }
            virtual void seterr(const std::string &err) { this->m_what = err; }
            friend std::ostream& operator<<(std::ostream& s, const omni::exception& e)
            { s << e.m_what; return s; }
            friend std::basic_ostream<wchar_t>& operator<<(std::basic_ostream<wchar_t>& s, const omni::exception& e) {
                s << e.m_what.c_str();
                return s;
            }
        protected:
            std::string m_what;
    };

    class some_other_exception : public your_namespace::exception {
        public:
            some_other_exception() : exception("some other exception happened") {}

    };
}

To use:

try {
    throw your_namespace::exception();
} catch (std::exception e) { // or const std::exception&
    std::cout << "error: " << e << std::endl;
    // or printf("error: %s\n", e.what()) for your C friends
}

try {
    throw your_namespace::exception("Here's an exception for you");
} catch (std::exception e) {
    std::cout << "error: " << e << std::endl;
}

try {
    throw your_namespace::some_other_exception();
} catch (std::exception e) {
    std::cout << "error: " << e << std::endl;
}

I hope that can help

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.