Получение информации о том, где исключения C++ выдаются в блоке выгоды?

У меня есть приложение C++, которое переносит значительные части кода в блоках попытки. Когда я ловлю исключения, я могу возвратить пользователя устойчивому состоянию, которое хорошо. Но я дольше не получаю дампы катастрофического отказа. Я действительно хотел бы выяснить, где в коде исключение происходит, таким образом, я могу зарегистрировать его и зафиксировать его.

Способность получить дамп, не останавливая приложение была бы идеальна, но я не уверен, что это возможно.

Есть ли некоторый способ, которым я могу выяснить, где исключение было выдано из блока выгоды? Если это полезно, я использую собственный msvc ++ на Windows XP и выше. Мой план состоит в том, чтобы просто зарегистрировать катастрофические отказы в файл на машинах различных пользователей и затем загрузить crashlogs, после того как они добираются до определенного размера.

8
задан Kate Gregory 13 June 2010 в 15:35
поделиться

5 ответов

Это возможно с использованием SEH (структурированная обработка исключений). Дело в том, что MSVC реализует исключения C ++ через SEH.С другой стороны, чистый SEH намного более мощный и гибкий.

Вот что тебе следует делать. Вместо использования чистых блоков try / catch C ++, подобных этому:

try
{
    DoSomething();
} catch(MyExc& exc)
{
    // process the exception
}

Вы должны обернуть внутренний блок кода DoSomething блоком SEH:

void DoSomething()
{
    __try {
        DoSomethingInner();
    }
    __except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
        // never get there
    }
}

void DumpEx(EXCEPTION_POINTERS* pExc)
{
    // Call MiniDumpWriteDump to produce the needed dump file
}

То есть внутри блока try / catch C ++ мы помещаем еще один необработанный блок SEH, который только сбрасывает все исключения, не перехватывая их.

См. здесь для примера использования MiniDumpWriteDump.

6
ответ дан 5 December 2019 в 12:07
поделиться

Вы можете настроить исключения так, чтобы они включали имена исходных файлов и номера строк. Для этого вам необходимо создать класс, производный от std :: exception , чтобы содержать информацию. В приведенном ниже примере у меня есть библиотека исключений для моего приложения, включая my_exception . У меня также есть traced_error , который является классом исключений шаблона, полученным из моих исключений на уровне приложения.Исключение traced_error содержит информацию об имени файла и номере строки и вызывает метод класса исключения уровня приложения ' what () для получения подробной информации об ошибке.

#include <cstdlib>
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;


template<class EX>
class traced_error : virtual public std::exception, virtual public EX
{
public:
    traced_error(const std::string& file, int line, const EX& ex)
    :   EX(ex),
        line_(line),
        file_(file)
    {       
    }

    const char* what() const
    {
        std::stringstream ss;
        static std::string msg;
        ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what();
        msg = ss.str().c_str();
        return msg.c_str();
    }

    int line_;
    std::string file_;
};

template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex)
{
    return traced_error<EX>(file, line, ex);
}


class my_exception : virtual public std::exception
{
public:
    my_exception() {};

    const char* what() const
    {
        return "my_exception's what";
    }
};

#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX))


int main()
{
    try
    {
        throwx(my_exception());
    }
    catch( const std::exception& ex )
    {
        cout << ex.what();
    }
    return 0;
}

Вывод этой программы:

Файл:. \ Main.cpp Строка: 57 Ошибка: my_exception's what

Вы также можете перепроектировать это так, чтобы исключения уровня приложения были производными от traced_error , а не наоборот, на случай, если вы предпочтете перехватить определенные исключения на уровне приложения. В вашей ловушке вы можете записать ошибку в файл журнала и создать файл дампа с помощью MiniDumpWriteDump () .

4
ответ дан 5 December 2019 в 12:07
поделиться

Что вам нужно, так это проанализировать стек, чтобы выяснить, откуда пришло исключение. Для msvc существует библиотека под названием dbghelp.dll , которая может помочь вам выйти из системы исключений. Как правило, я выхожу из файла минидампа и использую его для воспроизведения проблемы рядом с использованием правильной базы данных программы (файл pdb). Это работает в клиентских системах, которые не поставляются с исходным кодом или которым вы не хотите передавать pdbs.

1
ответ дан 5 December 2019 в 12:07
поделиться

Один прием, не зависящий от компилятора, заключается в том, чтобы обернуть оператор throw в функцию. Функция может выполнять другие функции, прежде чем выбросить исключение, например, записывать в файл журнала. Это также удобное место для установки точки останова. Если вы создадите макрос для вызова функции, вы можете автоматически включить __FILE__ и __LINE__, где произошел выброс.

1
ответ дан 5 December 2019 в 12:07
поделиться

Вы можете записывать дампы с помощью функции MiniDumpWriteDump .

Если вы используете исключения C ++, вы можете просто включить информацию о файле / строке / функции (чтобы вы видели ее как текст, если вы вызываете std :: exception.what ()) в любом месте, где вы бросаете это исключение (с использованием макросов ____FUNCTION____, ____FILE____ и ____LINE____).

Если вы пытаетесь перехватить исключения ОС, то, вероятно, лучшим выбором будет завершение работы приложения.

2
ответ дан 5 December 2019 в 12:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: