我有一个c ++应用程序,它在try块中包含大部分代码。当我捕获异常时,我可以将用户返回到稳定状态,这很好。但我不再接收崩溃转储了。我真的想弄清楚代码中的异常发生在哪里,所以我可以记录并修复它。
能够在不停止应用程序的情况下获得转储是理想的,但我不确定是否可行。
有什么方法可以找出catch块中抛出异常的位置?如果它有用,我在windows xp及更高版本上使用本机msvc ++。我的计划是简单地将崩溃记录到各个用户的计算机上的文件中,然后在达到一定大小后上传崩溃日志。
答案 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__
。