* TheDD said:
I was missing something:
$ cat -n throw.cc
1 #include <string>
2
3 class Ex
This should derive from std::runtime_error, or your catch in 'main' will
not.
With derivation from std::runtime_error you don't need the msg member.
4 {
5 public:
6 Ex(const char *msg, int no)
7 : msg(msg), no(no)
8 {
9 };
10
11 void doThrow(const char * file, int line)
Should be const (and that implies not modifying members).
Also, part of what makes a doThrow function useful is that it can be used
to throw an object you have a polymorphic reference to.
In order to support that it should also be virtual.
12 {
13 this->file = file;
14 this->line = line;
15
16 throw *this; // was missing
17 };
18
19 protected:
20 std::string msg;
21 std::string file;
22 int line;
23 int no;
24 };
I suggest something like (off the cuff)
class SourceCodeRef
{
private:
std::string myFileName;
int myLineNumber;
public:
SourceCodeRef( char const fileName[], int lineNumber )
: myFileName( fileName ), myLineNumber( lineNumber )
{}
std::string fileName() const { return myFileName; }
int lineNumber() const { return myLineNumber; }
};
#define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )
class Ex: public std::runtime_error
{
private:
int myErrorCode;
SourceCodeRef mySourceCodeRef;
public:
typedef std::runtime_error Base;
Ex( SourceCodeRef const& ref, char const message[], int errorCode )
: Base( message ), myErrorCode( errorCode ), mySourceCodeRef( ref )
{}
virtual SourceCodeRef const& sourceCodeRef() const
{
return mySourceCodeRef;
}
virtual int errorCode() const
{
return myErrorCode;
}
class MacroHelper
{
private:
SourceCodeRef myRef;
public:
MacroHelper( SourceCodeRef const& ref ): myRef( ref ) {}
void doThrow( char const message[], int errorCode ) const
{
throw Ex( myRef, message, errorCode );
}
};
};
#define THROW( classname, arguments ) \
classname::MacroHelper( SOURCECODEREF ).doThrow arguments
What this does is to separate concerns.
To the above Ex-class I would perhaps add
virtual void doThrow() const { throw *this; }
for reasons unrelated to constructor argument-passing in a class hierarchy.
25 // throw removed
26 #define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)
27
28 int main()
29 {
30 try
31 {
32 THROW(Ex, ("blah", 1));
33 return EXIT_SUCCESS;
34 }
35 catch( std::exception const& )
36 {
37 return EXIT_FAILURE;
38 }
39 }
Now my project compiles.
But with this macro, the exception is allocated on the stack. And i don't
know for the throw case. Must i create a copy in the heap or is "throw
*this" ok?
The effect of throwing is as if the copy constructor is invoked to copy
the object. The compiler may optimize that away. But the upshot is that
throwing is logically by value, not by reference, so there is no problem.