To start off, I have reached the solution I was looking for, but I would like comments and feedback on the solution I have reached and tips/tricks on making it more elegant. I am not satisfied with the underlying machinery of the solution though.
I am an advanced C programmer and most do object-based programming in C++. Please do not reply to this article with references to basic material or obvious tips.
An overview to the problem I was trying to solve ; I have written a very complex plugin for a webserver and it shows some bugs only with live use (to be specific a ISAPI Filter for Microsoft IIS). I was not given the go ahead to do live debugging on the server and it might not have helped track the bug anyway. In order to catch it I have to improve the instrumentation of my software.
The error codes in the server (win32 API numeric error codes) are mostly converted into exceptions but the exceptions weren't intelligent in any way... they were all stand-alone and did not derive from a standard heirarchy. I need a standard heirarchy to maintain sanity and I need the debug messages to be dynamic. std::exception as a base class was the obvious choice (wish I hadn't gone down that route now :D ) .
I want the exceptions to have a title and a body and I would obviously want to generate the body at runtime.The problem is that the what() method signature from std::exception defines the what as a const method.
Getting arround the const restriction leads to a ton of fidley code, which I should say I cannot accept it has made me hate aspects of the C++ language and the std library, I certainly would have faired better implementing the following in straight C, however saying this I want my faith restored in the language and shown why I am being unfair. The following solution has taken me about 10 hours of refactoring.
The custom exception for my project requires the following semantics.
Expand|Select|Wrap|Line Numbers
- class CustomException
- : public SStreamException
- {
- public :
- CustomException(char * file_in,DWORD line_in)
- : SStreamException(file_in,line_in) {}
- virtual const char * getType() const
- {
- return "testing";
- }
- virtual void getBody(std::stringstream & body_in) const
- {
- body_in << "My Sexy Body";
- }
- };
The Following is the underlying machinery to support the dynamic what() method.
Expand|Select|Wrap|Line Numbers
- #include <sstream>
- #include <string>
- #include <windows.h>
- /* Uses std::string to maintain the string. string::c_str() is a (const char *).
- * if std::stringstream::str()::c_str() is used the intermediary string object
- * vanishes at end of scope (return). Note that it derives from strinstream
- */
- class DynamicConstString
- : public std::stringstream
- {
- private :
- std::string * _privateConstString;
- public:
- DynamicConstString()
- : _privateConstString(NULL)
- {
- _privateConstString=new std::string();
- }
- ~DynamicConstString()
- {
- if(_privateConstString!=NULL)
- delete _privateConstString;
- }
- /* prior to a clear the string is constant */
- const char * getCString()
- {
- _privateConstString->assign((*this).str());
- return _privateConstString->c_str();
- }
- /* empty the string state in preparation of new data */
- void recycle()
- {
- _privateConstString->assign("");
- (*this).str(*_privateConstString);
- }
- };
- class SStreamException
- : public std::exception
- {
- char * file;
- DWORD line;
- /* For some reason (cannot remember) the following two objects need to be
- * heap allocated for const correctness */
- DynamicConstString * __debugMsgString;
- DynamicConstString * __bodyString;
- public:
- /* Following methods need to be defined by the Children */
- virtual const char * getType() const
- {
- return "Type Unspecified";
- }
- virtual void getBody(std::stringstream & _bodyString_in) const
- {
- _bodyString_in << "";
- }
- SStreamException(char * file_in, DWORD line_in)
- : file(file_in), line(line_in),__debugMsgString(NULL),__bodyString(NULL)
- {
- __debugMsgString=new DynamicConstString();
- __bodyString=new DynamicConstString();
- }
- ~SStreamException()
- {
- if(__debugMsgString!=NULL)
- delete __debugMsgString;
- if(__debugMsgString!=NULL)
- delete __bodyString;
- }
- const char * what() const throw()
- {
- __debugMsgString->recycle();
- __bodyString->recycle();
- std::stringstream & debugMsgString=*__debugMsgString;
- std::stringstream & bodyString=*__bodyString;
- debugMsgString << "Exception : " << getType() << std::endl;
- debugMsgString << "(" << file << ":" << line << ")" << std::endl;
- getBody(bodyString);
- /* if (bodyString.str()) is not used the pointer of (__bodystring) is used
- * for some reason. weird reason */
- debugMsgString << (bodyString.str());
- return __debugMsgString->getCString();
- }
- };
(1) Why the hell is what() marked as a const function ? is this braindead
or is there a justification for this.
(2) Have I circumvented the const correctness of std::exception: :what()
(3) is their a more elegant way to do this.
(4) are there more specialized libraries that do what I am trying to do for c++. (perhaps in boost ? Or Such).
(5) Could someone point me to some advanced articles on const correctness and the pitfalls of C++ object orientation.
(6) Is C++0x or the TR1 of boost attempting to make expressing such semantics in C++ better ? (perhaps the new garbage collector) And if so How ?
Looking forward to your feedback
Regards
Vain