Как получить номер строки ошибки в программе на С++

Я хочу обрабатывать ошибки в моей программе на С++, поэтому я создал некоторые классы исключений для управления этими ошибками, но я хочу указать, в какой строке в моей программе произошла ошибка.

Я передал макрос LINE конструктору моего класса исключений.

Например:

void f(int i){ // LINE A
  if(i<0)
    throw(OutOfRange("message", __LINE__); // LINE B
}

void main(){

  try{
    f(-6); // LINE C
  }
  catch(const OutOfRange& error){
    //do something
  }

}

В этом примере я могу получить только номер LINE B, но хочу получить номера LINE A и LINE C.

Любая идея, где и как использовать макрос LINE

Спасибо.

Ответ 1

Вы ищете трассировку стека, и нет никакого переносного способа ее получить. Что-то похожее может быть достигнуто с помощью:

struct SourcePoint
{
    const char *filename;
    int line;
    SourcePoint(const char *filename, int line)
      : filename(filename), line(line)
    { }
};

std::vector<SourcePoint> callstack;

struct SourcePointMarker
{
    SourcePointMarker(const char *filename, int line)
    {
        callstack.push_back(SourcePoint(filename, line);
    }

    ~SourcePointMarker()
    {
        callstack.pop_back();
    }
}

#define MARK_FUNCTION \
  SourcePointMarker sourcepointmarker(__FILE__, __LINE__);

Затем сразу после начала каждой функции (или точки интереса) вы просто добавляете строку... например

int myFunction(int x)
{
    MARK_FUNCTION
    ...
}

Используя этот подход в обработчиках ошибок, вы можете узнать, кто был вызван кем и т.д. (конечно, вы будете знать только функции или места, которые были связаны с MARK_FUNCTION). Если это необходимо только во время тестирования (а не в производстве), то, вероятно, вам следует просто включить дампы ядра и научиться запускать отладчик в анализе после вскрытия.

Ответ 2

Строка C была бы почти невозможна (я не могу придумать способ... за исключением того, что передал второй аргумент f, __LINE__.

Линия А выглядит следующим образом:

void f(int i){ const int lineA = __LINE__;
  if(i<0)
    throw(OutOfRange("message", __LINE__); // LINE B
}

Ответ 3

Вам нужна трассировка стека и отладчик. В стандартном С++ нет способа найти строку C, не передавая ее в качестве аргумента (f(-6, __LINE__)), и никак не может найти строку A.

Ответ 4

Структура CPPUNit использует макросы вместо функций. Таким образом, вы можете легко получить номер строки в том же месте, где вызывается макрос.

Я не думаю, что это правильный подход в общем смысле, но вам может показаться интересным взглянуть на то, как это сделали разработчики CPPUnit.