获取有关在catch块中抛出c ++异常的位置的信息?

时间:2010-06-11 22:27:45

标签: c++ exception visual-c++ logging

我有一个c ++应用程序,它在try块中包含大部分代码。当我捕获异常时,我可以将用户返回到稳定状态,这很好。但我不再接收崩溃转储了。我真的想弄清楚代码中的异常发生在哪里,所以我可以记录并修复它。

能够在不停止应用程序的情况下获得转储是理想的,但我不确定是否可行。

有什么方法可以找出catch块中抛出异常的位置?如果它有用,我在windows xp及更高版本上使用本机msvc ++。我的计划是简单地将崩溃记录到各个用户的计算机上的文件中,然后在达到一定大小后上传崩溃日志。

5 个答案:

答案 0 :(得分:6)

使用SEH(结构化异常处理)可以实现这一点。关键是MSVC通过SEH实现C ++异常。另一方面,纯SEH更强大,更灵活。

这就是你应该做的。而不是像这样使用纯C ++ try / catch块:

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

您应该使用SEH块包装内部代码块DoSomething

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
}

也就是说,在C ++ try / catch块中,我们放置了另一个原始SEH块,它只转储所有异常而不捕获它们。

有关使用MiniDumpWriteDump的示例,请参阅here

答案 1 :(得分:4)

可以设计您的例外以包含源文件名和&行号。为此,您需要创建一个派生自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错误:   <_pception是什么

您还可以重新设计它,以便应用程序级异常派生自traced_error而不是相反,以防您更愿意捕获特定的应用程序级异常。在catch中,您可以将错误记录到日志文件&amp;使用MiniDumpWriteDump()创建转储文件。

答案 2 :(得分:2)

您可以使用MiniDumpWriteDump函数编写转储。

如果你正在使用C ++异常,那么你可以简单地包含文件/行/函数信息(所以如果你调用std :: exception.what(),你会看到它作为文本)在你抛出它的任何地方异常(使用____FUNCTION __,____ FILE _____和____LINE __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

如果您试图捕获操作系统异常,那么崩溃应用程序可能是更好的选择。

答案 3 :(得分:1)

您需要分析堆栈以找出异常的来源。对于msvc,有一个名为dbghelp.dll的lib可以帮助您注销异常。一般来说,我所做的就是使用正确的程序数据库(pdb文件)注销minidump file and use this to replay the issue。这适用于没有源代码或您不想向其提供pdbs的客户系统。

答案 4 :(得分:1)

独立于编译器的一个技巧是将throw语句包装在函数中。该函数可以在抛出异常之前执行其他任务,例如记录到日志文件。它也是一个放置断点的便利场所。如果您创建一个宏来调用该函数,您可以自动包含发生投掷的__FILE____LINE__