我想优雅地处理所有内部错误,而不终止程序。
正如所讨论的,使用_set_se_translator捕获除以零的错误。
但是它没有捕捉到,例如,C运行时库错误-1073740777 (0xc0000417),这可能是由printf的格式字符串引起的,该字符串具有不应该的百分比符号。(这只是一个例子,当然我们应该检查这样的字符串)。要处理这些问题,需要使用_set_invalid_parameter_handler。
大约有10个这样的处理程序列出了这里。
此外,这个程序还将捕获未捕获的C++异常:SetUnhandledExceptionFilter。因此,它可以与__set__ .函数一起使用。(2008年MSVC中一篇关于使用它的文章。)
我希望捕获任何和所有的错误,以便我能够处理它们(通过日志记录、抛出一个现代的C++标准异常并返回一个特定于应用程序的错误代码)。有没有一个处理程序能捕捉到所有的东西?
在StackOverflow上也可以看到这个。
我正在使用2008。
发布于 2010-01-28 15:13:17
没有通用的处理程序。你需要安装每一个。我用过这样的方法:
///////////////////////////////////////////////////////////////////////////
template<class K, class V>
class MapInitializer
{
std::map<K,V> m;
public:
operator std::map<K,V>() const
{
return m;
}
MapInitializer& Add( const K& k, const V& v )
{
m[ k ] = v;
return *this;
}
};
///////////////////////////////////////////////////////////////////////////
struct StructuredException : std::exception
{
const char *const msg;
StructuredException( const char* const msg_ ) : msg( msg_ ) {}
virtual const char* what() const { return msg; }
};
///////////////////////////////////////////////////////////////////////////
class ExceptionHandlerInstaller
{
public:
ExceptionHandlerInstaller()
: m_oldTerminateHandler( std::set_terminate( TerminateHandler ) )
, m_oldUnexpectedHandler( std::set_unexpected( UnexpectedHandler ) )
, m_oldSEHandler( _set_se_translator( SEHandler ) )
{}
~ExceptionHandlerInstaller()
{
std::set_terminate( m_oldTerminateHandler );
std::set_unexpected( m_oldUnexpectedHandler );
_set_se_translator( m_oldSEHandler );
}
private:
static void TerminateHandler()
{
TRACE( "\n\n**** terminate handler called! ****\n\n" );
}
static void UnexpectedHandler()
{
TRACE( "\n\n**** unexpected exception handler called! ****\n\n" );
}
static void SEHandler( const unsigned code, EXCEPTION_POINTERS* )
{
SEMsgMap::const_iterator it = m_seMsgMap.find( code );
throw StructuredException( it != m_seMsgMap.end()
? it->second
: "Structured exception translated to C++ exception." );
}
const std::terminate_handler m_oldTerminateHandler;
const std::unexpected_handler m_oldUnexpectedHandler;
const _se_translator_function m_oldSEHandler;
typedef std::map<unsigned, const char*> SEMsgMap;
static const SEMsgMap m_seMsgMap;
};
///////////////////////////////////////////////////////////////////////////
// Message map for structured exceptions copied from the MS help file
///////////////////////////////////////////////////////////////////////////
const ExceptionHandlerInstaller::SEMsgMap ExceptionHandlerInstaller::m_seMsgMap
= MapInitializer<ExceptionHandlerInstaller::SEMsgMap::key_type,
ExceptionHandlerInstaller::SEMsgMap::mapped_type>()
.Add( EXCEPTION_ACCESS_VIOLATION, "The thread attempts to read from or write to a virtual address for which it does not have access. This value is defined as STATUS_ACCESS_VIOLATION." )
.Add( EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "The thread attempts to access an array element that is out of bounds, and the underlying hardware supports bounds checking. This value is defined as STATUS_ARRAY_BOUNDS_EXCEEDED." )
.Add( EXCEPTION_BREAKPOINT, "A breakpoint is encountered. This value is defined as STATUS_BREAKPOINT." )
.Add( EXCEPTION_DATATYPE_MISALIGNMENT, "The thread attempts to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on. This value is defined as STATUS_DATATYPE_MISALIGNMENT." )
.Add( EXCEPTION_FLT_DENORMAL_OPERAND, "One of the operands in a floating point operation is denormal. A denormal value is one that is too small to represent as a standard floating point value. This value is defined as STATUS_FLOAT_DENORMAL_OPERAND." )
.Add( EXCEPTION_FLT_DIVIDE_BY_ZERO, "The thread attempts to divide a floating point value by a floating point divisor of 0 (zero). This value is defined as STATUS_FLOAT_DIVIDE_BY_ZERO." )
.Add( EXCEPTION_FLT_INEXACT_RESULT, "The result of a floating point operation cannot be represented exactly as a decimal fraction. This value is defined as STATUS_FLOAT_INEXACT_RESULT." )
.Add( EXCEPTION_FLT_INVALID_OPERATION, "A floatin point exception that is not included in this list. This value is defined as STATUS_FLOAT_INVALID_OPERATION." )
.Add( EXCEPTION_FLT_OVERFLOW, "The exponent of a floating point operation is greater than the magnitude allowed by the corresponding type. This value is defined as STATUS_FLOAT_OVERFLOW." )
.Add( EXCEPTION_FLT_STACK_CHECK, "The stack has overflowed or underflowed, because of a floating point operation. This value is defined as STATUS_FLOAT_STACK_CHECK." )
.Add( EXCEPTION_FLT_UNDERFLOW, "The exponent of a floating point operation is less than the magnitude allowed by the corresponding type. This value is defined as STATUS_FLOAT_UNDERFLOW." )
.Add( EXCEPTION_GUARD_PAGE, "The thread accessed memory allocated with the PAGE_GUARD modifier. This value is defined as STATUS_GUARD_PAGE_VIOLATION." )
.Add( EXCEPTION_ILLEGAL_INSTRUCTION, "The thread tries to execute an invalid instruction. This value is defined as STATUS_ILLEGAL_INSTRUCTION." )
.Add( EXCEPTION_IN_PAGE_ERROR, "The thread tries to access a page that is not present, and the system is unable to load the page. For example, this exception might occur if a network connection is lost while running a program over a network. This value is defined as STATUS_IN_PAGE_ERROR." )
.Add( EXCEPTION_INT_DIVIDE_BY_ZERO, "The thread attempts to divide an integer value by an integer divisor of 0 (zero). This value is defined as STATUS_INTEGER_DIVIDE_BY_ZERO." )
.Add( EXCEPTION_INT_OVERFLOW, "The result of an integer operation causes a carry out of the most significant bit of the result. This value is defined as STATUS_INTEGER_OVERFLOW." )
.Add( EXCEPTION_INVALID_DISPOSITION, "An exception handler returns an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception. This value is defined as STATUS_INVALID_DISPOSITION." )
.Add( EXCEPTION_INVALID_HANDLE, "The thread used a handle to a kernel object that was invalid (probably because it had been closed.) This value is defined as STATUS_INVALID_HANDLE." )
.Add( EXCEPTION_NONCONTINUABLE_EXCEPTION, "The thread attempts to continue execution after a non-continuable exception occurs. This value is defined as STATUS_NONCONTINUABLE_EXCEPTION." )
.Add( EXCEPTION_PRIV_INSTRUCTION, "The thread attempts to execute an instruction with an operation that is not allowed in the current computer mode. This value is defined as STATUS_PRIVILEGED_INSTRUCTION." )
.Add( EXCEPTION_SINGLE_STEP, "A trace trap or other single instruction mechanism signals that one instruction is executed. This value is defined as STATUS_SINGLE_STEP." )
.Add( EXCEPTION_STACK_OVERFLOW, "The thread uses up its stack. This value is defined as STATUS_STACK_OVERFLOW." );
然后在main或app init中,我这样做:
BOOL CMyApp::InitInstance()
{
ExceptionHandlerInstaller ehi;
// ...
}
请注意,这会将结构化异常转换为常规异常,但只需打印错误消息就可以处理终止(例如,当no每秒()函数抛出异常时,终止就会被调用)。对于所有不同类型的错误,您不太可能使用单个处理程序,这就是为什么它们不提供它的原因。
发布于 2010-01-28 15:14:30
我要提醒大家不要这样做。
内部错误不可恢复。如果您除以零或其他-程序是不可恢复的。
如果将终止处理程序转换为继续运行程序的东西,则无法保证程序的状态,而且以后您可能会以不同的方式崩溃和损坏。例如,假设程序在终止时持有一些锁、或其他资源!
让我们举一个糟糕的例子:
void log(const char* fmt,...) {
lock(logfile);
va_args...
fvprintf(logfile,fmt,__... <--- this line calls the terminator
unlock(logfile);
}
如果你不终止程序会发生什么?当下一次有人尝试记录某件东西时,程序会发生什么情况?
我再强调也不为过--你应该使用挂钩终止的方法来进行额外的日志记录,而不是其他任何事情。你以后应该继续退出。
有一个完全不同的错误类别,可以被截获:
许多API使用返回码与调用方进行通信,以指示错误条件。使用宏或助手函数检查这些返回代码并将它们转换为异常是合适的。这是因为这个选择在您可以看到的代码中。
如果您重写了_set_errno处理程序或其他什么东西,您就会导致没有编写的代码期望setter正常返回不返回,而且它可能还没有完成清理。
https://stackoverflow.com/questions/2155442
复制相似问题