C++异常处理机制
异常处理是C++的一项语言机制,用于在程序中处理异常事件。异常事件在C++中表示为异常对象。异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统为程序设置当前异常对象,然后执行程序的当前异常处理代码块,在包含了异常出现点的最内层的try块,依次匹配catch语句中的异常对象(只进行类型匹配,catch参数有时在catch语句中并不会使用到)。若匹配成功,则执行catch块内的异常处理语句,然后接着执行try…catch…块之后的代码。如果在当前的try…catch…块内找不到匹配该异常对象的catch语句,则由更外层的try…catch…块来处理该异常;如果当前函数内所有的try…catch…块都不能匹配该异常,则递归回退到调用栈的上一层去处理该异常。如果一直退到主函数main()都不能处理该异常,则调用系统函数terminate()终止程序。
一、抛异常---throw
throw是个关键字,与抛出表达式构成了throw语句。其语法为:throw 表达式;throw语句必须包含在try块中,也可以是被包含在调用栈的外层函数的try块中。执行throw语句时,throw表达式将作为对象被复制构造为一个新的对象,称为异常对象。异常对象放在内存的特殊位置,该位置既不是栈也不是堆,在window上是放在线程信息块TIB中。这个构造出来的新对象与本级的try所对应的catch语句进行类型匹配。如下:
在vc++里,throw关键字其实是对RaiseException函数的封装,代码如下:
__declspec(noreturn) extern "C" void __stdcall #if !defined(_M_ARM) || defined(_M_ARM_NT) _CxxThrowException( #else __CxxThrowException( #endif void* pExceptionObject, // The object thrown _ThrowInfo* pThrowInfo // Everything we need to know about it ) { EHTRACE_ENTER_FMT1("Throwing object @ 0x%p", pExceptionObject); static const EHExceptionRecord ExceptionTemplate = { // A generic exception record EH_EXCEPTION_NUMBER, // Exception number EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume) NULL, // Additional record (none) NULL, // Address of exception (OS fills in) EH_EXCEPTION_PARAMETERS, // Number of parameters { EH_MAGIC_NUMBER1, // Our version control magic number NULL, // pExceptionObject NULL, #if _EH_RELATIVE_OFFSETS NULL // Image base of thrown object #endif } // pThrowInfo }; EHExceptionRecord ThisException = ExceptionTemplate; // This exception ThrowInfo* pTI = (ThrowInfo*)pThrowInfo; if (pTI && (THROW_ISWINRT( (*pTI) ) ) ) { ULONG_PTR *exceptionInfoPointer = *reinterpret_cast<ULONG_PTR**>(pExceptionObject); exceptionInfoPointer--; // The pointer to the ExceptionInfo structure is stored sizeof(void*) infront of each WinRT Exception Info. WINRTEXCEPTIONINFO** ppWei = reinterpret_cast<WINRTEXCEPTIONINFO**>(exceptionInfoPointer); pTI = (*ppWei)->throwInfo; (*ppWei)->PrepareThrow( ppWei ); } // // Fill in the blanks: // ThisException.params.pExceptionObject = pExceptionObject; ThisException.params.pThrowInfo = pTI; #if _EH_RELATIVE_OFFSETS PVOID ThrowImageBase = RtlPcToFileHeader((PVOID)pTI, &ThrowImageBase); ThisException.params.pThrowImageBase = ThrowImageBase; #endif // // If the throw info indicates this throw is from a pure region, // set the magic number to the Pure one, so only a pure-region // catch will see it. // // Also use the Pure magic number on Win64 if we were unable to // determine an image base, since that was the old way to determine // a pure throw, before the TI_IsPure bit was added to the FuncInfo // attributes field. // if (pTI != NULL) { if (THROW_ISPURE(*pTI)) { ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1; } #if _EH_RELATIVE_OFFSETS else if (ThrowImageBase == NULL) { ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1; } #endif } // // Hand it off to the OS: // EHTRACE_EXIT; #if defined(_M_X64) && defined(_NTSUBSET_) RtlRaiseException( (PEXCEPTION_RECORD) &ThisException ); #else RaiseException( ThisException.ExceptionCode, ThisException.ExceptionFlags, ThisException.NumberParameters, (PULONG_PTR)&ThisException.params ); #endif }
- 上一篇: 仅通过转储来排除内存泄漏
- 下一篇: 使用Java中的InputStream读取文件数据