Home >Backend Development >C#.Net Tutorial >Exception handling skills for C++ programs
Handling exceptions in C++ comes with a few implicit limitations at the language level, but in some cases you can get around them. By learning various ways to exploit exceptions, you can produce more reliable applications. Preserving exception source information In C++, whenever an exception is caught within a handler, information about the exception source is unknown. The specific source of the exception can provide a lot of important information to better handle the exception, or provide some information that can be appended to the error log for later analysis. To solve this problem, you can generate a stack trace in the exception object's constructor during the throw statement. ExceptionTracer is a class that demonstrates this behavior. Listing 1. Generating a stack trace in the exception object constructor // Sample PRogram:
// Compiler: gcc 3.2.3 20030502
// linux: Red Hat #include
#include < ;signal.h> #include
#include
{
public:
ExceptionTracer()
{
void * array[25];
int nSize = backtrace (array, 25);
char ** symbols = backtrace_symbols(array, nSize);
for (int i = 0; i < nSize; i++)
{
cout << symbols[ i] << endl;
} free(symbols);
}
}; Governance Signals Whenever a process performs a nasty action that causes the Linux? kernel to emit a signal, the signal must be processed. Signal handlers usually release some important resources and terminate the application. In this case, all object instances on the stack are in an undestructed state. On the other hand, if these signals are converted into C++ exceptions, then you can call their constructors gracefully and arrange multiple layers of catch blocks to better handle these signals. The SignalExceptionClass, defined in Listing 2, provides an abstraction for representing C++ exceptions that may be signaled by the kernel. SignalTranslator is a template class based on SignalExceptionClass, which is usually used to implement conversion to C++ exceptions. At any instant, only one signal handler can handle a signal for an active process. Therefore, SignalTranslator adopts the singleton design pattern. The overall concept is demonstrated through the SegmentationFault class for SIGSEGV and the FloatingPointException class for SIGFPE. Listing 2. Convert signals into exceptions
template
{
private:
class SingleTonTranslator
{
public:
SingleTonTranslator()
{
signal( SignalExceptionClass::GetSignalNumber(),
SignalHandler);
} static void SignalHandler(int)
{
throw SignalExceptionClass();
}
}; public:
SignalTranslator()
{
static SingleTonTranslator s_objTranslator;
}
}; // An example for SIGSEGV
class SegmentationFault : public ExceptionTracer, public
exception
{
public:
static int GetSignalNumber() {return SIGSEGV; }
}; SignalTranslator
} ; SignalTranslator
g_objFloatingPointExceptionTranslator; Managing exceptions in constructors and destructors It is impossible for every ANSI C++ to catch exceptions during the construction and destruction of global (static global) variables. Therefore, ANSI C++ does not recommend throwing exceptions in the constructors and destructors of classes whose instances may be defined as global instances (static global instances). In other words, never define global (static global) instances for classes whose constructors and destructors may throw exceptions. However, assuming a specific compiler and a specific system, it might be possible to do so, and fortunately, this is exactly the case with GCC on Linux. This can be demonstrated using the ExceptionHandler class, which also adopts the singleton design pattern. Its constructor registers an uncaught handler. Because only one uncaught handler can handle an active process at a time, the constructor should be called only once, hence the singleton pattern. The global (static global) instance of ExceptionHandler should be defined before the actual global (static global) variable in question is defined. Listing 3. Handling exceptions in constructors class ExceptionHandler
{
private:
class SingleTonHandler
{
public:
SingleTonHandler()
{
set_terminate(Handler);
} static void Handler()
{
// Exception from constrUCtion/destruction of global variables try
{
// re-throw throw;
}
catch (SegmentationFault &)
{
cout << “SegmentationFault” << endl;
}
catch (FloatingPointException &)
{
cout << “FloatingPointException” << endl;
}
catch (...)
{
cout << “Unknown Exception” << endl;
} //if this is a thread performing some core activity
abort();
// else if this is a thread used to service requests
// pthread_exit();
}
}; public:
ExceptionHandler()
{
static SingleTonHandler s_objHandler;
}
}; ////////////////////////////////////////////////////////////////////////// class A
{
public:
A()
{
//int i = 0, j = 1/i;
*(int *)0 = 0;
}
}; // Before defining any global variable, we define a dummy instance
// of ExceptionHandler object to make sure that
// ExceptionHandler::SingleTonHandler::SingleTonHandler() is
invoked
ExceptionHandler g_objExceptionHandler;
A g_a; ////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[])
{
return 0;
} 处理多线程程序中的异常 有时一些异常没有被捕捉,这将造成进程异常中止。不过很多时候,进程包含多个线程,其中少数线程执行核心应用程序逻辑,同时,其余线程为外部请求提供服务。假如服务线程因编程错误而没有处理某个异常,则会造成整个应用程序崩溃。这一点可能是不受人们欢迎的,因为它会通过向应用程序传送不合法的请求而助长拒绝服务攻击。为了避免这一点,未捕捉处理程序可以决定是请求异常中止调用,还是请求线程退出调用。清单3 中 ExceptionHandler::SingleTonHandler::Handler() 函数的末尾处展示了该处理程序。 结束语 我简单地讨论了少许 C++ 编程设计模式,以便更好地执行以下任务: ·在抛出异常的时候追踪异常的来源。
·将信号从内核程序转换成 C++ 异常。
·捕捉构造和/或析构全局变量期间抛出的异常。
·多线程进程中的异常处理。
以上就是C++程序的异常处理技巧的内容,更多相关文章请关注PHP中文网(www.php.cn)!