華文網

Linux的C ++異常處理技巧

Linux的C ++異常處理技巧

處理內置語言限制的四種技巧

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603

保留異常源資訊

在C ++中,每當異常在處理常式中被捕獲時,有關異常源的資訊將丟失。異常的確切來源可以提供很多重要資訊來更好地處理它,或者可以將資訊附加到錯誤日誌中以進行後驗。

為了處理這個問題,你可以在throw異常語句的異常物件的構造函數中生成一個堆疊跟蹤。ExceptionTracer 是一個演示此行為的類。

清單1.在異常物件構造函數中生成堆疊跟蹤

// Sample Program:

// Compiler: gcc 3.2.3 20030502

// Linux: Red Hat

#include

#include

#include

#include

using namespace std;

/////////////////////////////////////////////

class ExceptionTracer

{

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);

}

};

管理信號

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603

每當一個進程執行違規動作,使得Linux™內核提出一個信號,則必須處理該信號。信號處理常式通常釋放重要資源並終止應用程式。在這種情況下,堆疊中的所有物件實例都將保持未被破壞。

另一方面,如果將這些信號轉換為C ++異常,則可以優雅地調用它們的析構函數並程式設計多個catch塊級別,以更好地處理信號。

但是,您必須記住以下內容:

如果信號類型是非同步的或不可恢復的,則這種方法將不起作用。並非所有信號類型都是同步的,這意味著該進程中的不同執行緒可能會接收它們。此外,信號類型可能無法恢復,並且該過程必須關閉。為了增加複雜性,

一個內核上的信號類型可以是同步的,另一個內核上的信號類型是非同步的。你不能編寫一個適用於所有的代碼。

某些Linux / UNIX系統需要進行堆疊修復,才能從信號處理常式中拋出C ++異常。同樣,堆疊修復的確切性質取決於你的內核。

一般來說,該平臺上任何JVM轉換為Java異常的信號也可以轉換為C ++異常。

SignalExceptionClass在清單2中定義,它提供了一個表示內核可能上升的信號的C ++異常的抽象。 SignalTranslator是一個基於範本類 SignalExceptionClass,

實際上是翻譯。每個進程每個信號只能有一個信號處理器在任何時刻都處於活動狀態。因此, SignalTranslator採用單身設計模式。整個概念使用SegmentationFaultSIGSEGV的FloatingPointException類和SIGFPE 的類來演示。

清單2.將信號轉換為異常

template class SignalTranslator

{

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 g_objSegmentationFaultTranslator;

// An example for SIGFPE

class FloatingPointException : public ExceptionTracer, public exception

{

public:

static int GetSignalNumber() {return SIGFPE;}

};

SignalTranslator g_objFloatingPointExceptionTranslator;

管理構造函數和析構函數中的異常

更多學習資料,更多學習視頻,

免費課程:C/C++ 8群 491994603

根據ANSI C ++,在構建和銷毀全域(靜態全域)變數)期間,捕獲異常是不可能的。因此,ANSI C ++不建議在實例可以全域定義(靜態 - 全域)的類的構造函數和析構函數中拋出異常。另一種說法是,從來沒有定義一個類的全域(靜態全域)實例,它的構造函數或析構函數可能會拋出異常。但是,如果您假設具體的編譯器和特定的系統,那麼可能是可行的,幸運的是,在Linux上使用GCC。

這是使用ExceptionHandler類,它再次採用單例設計模式。它的構造函數註冊一個未被捕獲的處理常式。由於每個進程一次只能有一個未捕獲的處理常式,所以構造函數只能被調用一次; 因此,單身人士模式的原因。ExceptionHandler在定義全域(靜態全域)變數之前,應該定義全域(靜態全域)實例。

清單3.在構造函數中處理異常

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;

}

};

ExceptionHandler g_objExceptionHandler;

A g_a;

//////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])

{

return 0;

}

處理多執行緒程式中的異常

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603

有時例外會被抓住,這將導致進程中止。然而,很多時候,進程包含多個執行緒,其中一些執行緒執行核心應用程式邏輯,而其餘執行緒執行外部請求。如果服務執行緒由於程式設計錯誤而無法處理異常,則會殺死整個應用程式。這可能是不受歡迎的,因為它通過向應用程式提供非法請求來促進拒絕服務攻擊。為了避免這種情況,未捕獲的處理常式可以決定是否調用中止或執行緒退出調用。這ExceptionHandler::SingleTonHandler::Handler() 在清單3 中的功能結束時得到了展示。

結論

我簡要討論了一些C ++程式設計設計模式,以更好地執行以下任務:

在正在拋出異常的過程中跟蹤異常的來源。

將信號從內核轉換為C ++異常。

在構建和/或破壞全域變數期間捕獲異常。

多執行緒進程中的異常處理。

希望您能夠採用這些技術來開發無障礙代碼。

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603

它再次採用單例設計模式。它的構造函數註冊一個未被捕獲的處理常式。由於每個進程一次只能有一個未捕獲的處理常式,所以構造函數只能被調用一次; 因此,單身人士模式的原因。ExceptionHandler在定義全域(靜態全域)變數之前,應該定義全域(靜態全域)實例。

清單3.在構造函數中處理異常

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;

}

};

ExceptionHandler g_objExceptionHandler;

A g_a;

//////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])

{

return 0;

}

處理多執行緒程式中的異常

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603

有時例外會被抓住,這將導致進程中止。然而,很多時候,進程包含多個執行緒,其中一些執行緒執行核心應用程式邏輯,而其餘執行緒執行外部請求。如果服務執行緒由於程式設計錯誤而無法處理異常,則會殺死整個應用程式。這可能是不受歡迎的,因為它通過向應用程式提供非法請求來促進拒絕服務攻擊。為了避免這種情況,未捕獲的處理常式可以決定是否調用中止或執行緒退出調用。這ExceptionHandler::SingleTonHandler::Handler() 在清單3 中的功能結束時得到了展示。

結論

我簡要討論了一些C ++程式設計設計模式,以更好地執行以下任務:

在正在拋出異常的過程中跟蹤異常的來源。

將信號從內核轉換為C ++異常。

在構建和/或破壞全域變數期間捕獲異常。

多執行緒進程中的異常處理。

希望您能夠採用這些技術來開發無障礙代碼。

更多學習資料,更多學習視頻,免費課程:C/C++ 8群 491994603