Reputation: 145
I want to do some exception handling. I plan on using the __LINE__
and __FILE__
macros.
I have some header Vectors.hpp in which I implement some class for a vector structure. In this class I implement the operator []
and I want to throw an exception each time this operator is used with an out of bounds index. I test this class in some source test.cpp. I want then to be able to see the exact line in test.cpp where this happened.
However I know that the __LINE__
macro is disabled every time you include some header, so what I got is the line in Vectors.hpp where I handle the exception and not the line in test.cpp. Is there a nice way to get around this? Or, how would one implement his own __LINE__
macro?
Upvotes: 2
Views: 342
Reputation: 1736
Simple, you have to add that information when you catch the exception, very usually we create an class extending std::exception with some additional attributes for mounting a clear error message, on which you include the __LINE__
, __FILE__
or even __FUNCTION__
This one also answers that: Getting information about where c++ exceptions are thrown inside of catch block?
Upvotes: 0
Reputation: 39089
The __LINE__
macro is never disabled. It is expanded where you write it. There are two ways to write code (more precisely, there are two ways to produce tokens):
If you have it is some file foo.cpp
like this (just exemplary, that's very bad code actually)
class Foo {
public:
Frob operator[] (size_t) { throw __LINE__ }
};
then __LINE__
is always 3 and __FILE__
is always foo.cpp
.
That's because the macros are expanded where they are used. The solution would be to find a way to get them expanded where you want it, and the only way to do so is to define another macro:
#define safe_subscript(foo, index) \
try {foo[index];} \
catch(...) { std::cout << __LINE__ << '\n'; }
....
safe_subscript(foo, 256);
But as you see, this leads to quite ugly code and workarounds.
Real Solution: Just throw an exception upon out of bounds (throw std::out_of_range
), or do it like the standard library:
T& operator[] (size_type i) { return store_[i]; }
T& at (size_type i) { if (i>size_) throw std::out_of_range("crap");
return store_[i]; }
T operator[] (size_type i) const { return store_[i]; }
T at (size_type i) const { if (i>size_) throw std::out_of_range("crap");
return store_[i]; }
If your user receives an exception, he is ought to debug where he/she/it made a programming error.
Upvotes: 5
Reputation: 1382
You could pass the current line as part of the exception. Define your exception as
struct MyException : public std::exception {
MyException(const char* line) : errorLine(line);
const char* errorLine;
};
And use it as follows:
if (isError())
throw MyException(__LINE__);
Upvotes: 1