user1566114
user1566114

Reputation: 145

Disabled __LINE__ macro?

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

Answers (3)

Rodrigo Gurgel
Rodrigo Gurgel

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

Sebastian Mach
Sebastian Mach

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):

  • write it manually
  • use the preprocessor to write code

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

jarmond
jarmond

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

Related Questions