How should I write an efficient exception class to show the error that can be prevented by fixing the source code mistakes before run-time?
This is the reason I chose std::invalid_argument
.
My exception class(not working, obviously):
class Foo_Exception : public std::invalid_argument
{
private:
std::string Exception_Msg;
public:
explicit Foo_Exception( const std::string& what_arg );
virtual const char* what( ) const throw( );
};
explicit Foo_Exception::Foo_Exception( const std::string& what_arg ) // how should I write this function???
{
Exception_Msg.reserve( 130000 );
Exception_Msg = "A string literal to be appended, ";
Exception_Msg += std::to_string( /* a constexpr int */ );
Exception_Msg += /* a char from a const unordered_set<char> */;
}
const char* Foo_Exception::what( ) const throw( )
{
return Exception_Msg.c_str( );
}
An if
block that throws Foo_Exception
:
void setCharacter( const char& c )
{
if ( /* an invalid character (c) is passed to setCharacter */ )
{
try
{
const Foo_Exception foo_exc;
throw foo_exc;
}
catch( const Foo_Exception& e )
{
std::cerr << e.what( );
return;
}
}
/*
rest of the code
*/
}
int main( )
{
setCharacter( '-' ); // dash is not acceptable!
return 0;
}
As you can see, I need to concatenate Exception_Msg
with a few substrings in order to form the completed message. These substrings are not only string literals but also constexpr int
s and char
s from a static std::unordered_set<char>
. That's why I used std::string because it has the string::operator+=
which is easy to work with. And needless to say, my goal is to reduce heap allocations down to only 1.
Another very important question is that where should I place the handler( the try-catch )? Inside the main()
wrapping the setCharacter()
or keep it inside setCharacter
?
Please make a good and standard custom exception class similar to the above. Or write your own. Thanks in advance.
I solved this problem based on the feedback that I received from others through comments and answers. So I decided to leave my own answer/solution here for future readers.
Below can be seen what I came up with after much thought and research. This solution is fairly simple and readable.
Here is the exception class interface:
Foo_Exception.h
#include <exception>
class Foo_Exception : public std::invalid_argument
{
public:
explicit Foo_Exception( const std::string& what_arg );
};
And here is its implementation:
Foo_Exception.cpp
#include "Foo_Exception.h"
Foo_Exception::Foo_Exception( const std::string& what_arg )
: std::invalid_argument( what_arg )
{
}
A function that throws Foo_Exception
:
Bar.cpp
#include "Bar.h"
#include "Foo_Exception.h"
void setCharacter( const char& c )
{
if ( /* an invalid character (c) is passed to setCharacter */ )
{
std::string exceptionMsg;
exceptionMsg.reserve( 130000 );
exceptionMsg = "A string literal to be appended, ";
exceptionMsg += std::to_string( /* a constexpr int */ );
exceptionMsg += /* a char from a const unordered_set<char> */;
throw Foo_Exception( exceptionMsg );
}
/*
rest of the code
*/
}
How to handle the exception:
main.cpp
#include <iostream>
#include "Bar.h"
#include "Foo_Exception.h"
int main( )
{
try
{
setCharacter( '-' ); // The dash character is not valid! Throws Foo_Exception.
}
catch ( const Foo_Exception& e )
{
std::cerr << e.what( ) << '\n';
}
return 0;
}
Summary of the Changes:
Notice how there's no need for a what()
function since the compiler generates it implicitly because Foo_Exception
inherits from std::invalid_argument
.
Also, the process of creating the exception message was moved from the Foo_Exception
's ctor to the body of the function setCharacter
which actually throws the aforementioned exception. This way, the Foo_Exception
's ctor is not responsible for creating the message. Instead, it is created in the body of the function that throws and is then passed to the ctor of Foo_Exception
to initialize the new exception object.
The data member std::string Exception_Msg
was also removed from Foo_Exception
as it wasn't needed anymore.
Finally, the try-catch block was moved to main()
so that it now wraps around setCharacter()
and catches a Foo_Exception
object that it might throw.
Final word: Any suggestions to further improve my answer is highly appreciated. Thanks a ton for all the feedback.