0

I have read answers to following questions ->

c++ exception : throwing std::string

c++ Exception Class Design

My requirement is to catch exceptions and allow a mechanism to reformat the error messages and then re-throw the exceptions. So I thought of writing my exception class which will provide a method to reformat the error message at various catch points.To make reformatting easy, I'm embedding a string object in myexception_base class.

I have also referred to this article -> http://www.boost.org/community/error_handling.html which clearly says not to embed string objects in exception classes.

The article also has a quote "Peter Dimov makes an excellent argument that the proper use of a what() string is to serve as a key into a table of error message formatters." but it does not elaborate on it any further.

I have written the code as given below and my questions are -

1) If I don't embed a string object in my exception class, it will make it difficult to reformat the what messages. Please tell me How shall I approach to my requirement without embedding a string object in my exception class?

2) If I carry on with my current approach of embedding a string object and providing a method to format error message. Is my way of handling some scenarios correct ? (Issue 1 and Issue 2 in which error msg doesn't get formatted)

Issue 1 - wrong exception getting propagated to catch points ? Issue 2 - Error Message not getting formatted in some scenarios ? Issue 1 and Issue 2 are mentioned in comments in code below.

Kindly have a look at the code. I have given lot of comments in code so lines of code has increased but if I remove the comments it has very less lines of code.

#include <string>
#include <exception>
#include <iostream>
using namespace std;

class myexception_base : public exception {

private:
    string error_msg;
public:
    myexception_base(const char* str) : error_msg(str) {    
        // std::string here here can throw an exception while error_msg 
        //initialisation through MIL. 
        // myexception_base object will not be constructed 
        // and wrong exception will be  propagated to catch point(Issue 1)
    }

    const char* what() const throw() {  

        try {
            return error_msg.c_str();   
        } catch (...) {}

        // c_str can throw. 
        // I can't remove throw specification from what()
        // because what() in base std::exception has throw() specification  
        // In case c_str() throws an exception program will terminate
        // So to stop abnormal termination of program c_str 
        // is wrapped in a try catch block to ignore std::string exception
        // program will not terminate but what message is not reformatted
        // in such scenario (Issue 2)
    }

    void append_error_msg(const char* str) {

        error_msg.append(str);      
        // append can throw
        // Again error_msg will not be formatted (Issue 2)
    }
    ~myexception_base() throw() {
    }
};

void f();
void f2();

void f() {
    throw myexception_base("Error Msg1");
}

void f2() {

    //Some intermediate Catch point will reformat e.what() msg
    //by appending an error msg2
    try {
        f();
    }
    catch (myexception_base& e) {

        e.append_error_msg(": Error Msg2");
        throw;
    }
}


int main () {
    try {
        f2();
    }
    catch(const exception& e) {
        // Finally the exception is caught in the upper most layer
        // and proper error_msg is given to user
        cout<<e.what()<<"\n";
    }
}
Community
  • 1
  • 1
Ameliorator
  • 417
  • 1
  • 5
  • 10

1 Answers1

2

According to the boost documentation embedding classes which might throw during their lifetime are not an excellent candidate to be used in the exception handler mechanism, so I would like to suggest that you will simply use the good old C way of handling strings. It will require some extra effort to bring it up and running but with them you have eliminated one source of error.

So, basically there are two approaches:

  1. In the myexception_base you declare the error_msg as being an array of N chars. In the append_error_msg you carefully check that the length of the NEW string (after the append) is not greater than N and if it is not, then you use strcat or one of the other C string handling methods. This approach might be good, since it does not allow memory leaks through the exception handling mechanism, however you can have only a limited length of error message.

  2. In the myexception_base you declare the error_msg as being a char* (a char pointer). In the constructor you callocmemory for it (do not use new since new might throw) and in the append_error_message you realloc the pointer to be the new size (ie. old size + string to be appended.size + 1 for the 0) and then memcpy to the requested position (ie. at the position of the end of the old string in the newly allocated string). Of course, do not forget to check all the allocations/re-allocations that they have returned a valid value otherwise you might get funny behavior. And last, but not least, to avoid the classical memory leaks, free the memory of the char* in the destructor.

Good luck!

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • Thanks for your answer.But I don't want to use the C way to handle this. I guess there will be some C++ way to design exception classes which will have a use case to reformat error messages. I'm just hoping someone would have come across a similar use case earlier and would have solved this with a better design than what I'm doing using C++ way. – Ameliorator Dec 21 '11 at 12:44