2011-09-28 61 views
-2

我試圖安全地從預計發生的分段錯誤中恢復。我試圖避免使用我的canAlloc()函數在這裏檢查。當canAllow返回false時,A0(如果你沒有看到它,就是Ackermann的)應該拋出一個我可以在主要方法中捕獲的異常。 checkTable和saveInTable都是使用map<int hash, int value>存儲A0返回的函數。在C++中使用C動態內存函數以避免分段錯誤

bool canAlloc(){ 
    bool reBool = false; 
    int * memch = (int*)calloc (10000, sizeof(int)); 
    reBool = (memch != NULL); 
    free(memch); 
    return reBool; 
    } 


    int A0(int m, int n){ 
if(!canAlloc()) throw; 

int reInt = checkReturnTable(m,n); 
if(reInt == -1){   
    if(m == 0){ 
     return n + 1; 
    } else if(m > 0){ 
      if(n == 0){ 
       reInt = A0(m-1,1); 
      } else if(n > 0){ 
       reInt = A0(m-1, A0(m,n-1)); 
      } 
    } 
    saveInReturnTable(m,n,reInt); 
    return reInt; 
} else return reInt; 
} 

從評論:

在主要我有一個try-catch塊捕捉任何異常try{} catch(...){}。據我瞭解,這三個時期應該會引發任何異常。據我所知,throw關鍵字拋出沒有任何說明符的異常,但仍然可以被三個點捕獲。

+3

「'throw'」?這又是什麼語言? – cnicutar

+0

我不明白你的問題。那裏的支票並沒有告訴你很多。您可以在一個時間點分配一些內存並不意味着您可以在不同的時間點分配內存。 – johannes

+0

'扔'什麼? :) –

回答

4

分段錯誤不是C++異常。這表示程序失敗,導致操作系統向您的進程發送SIGSEGV信號。您將無法直接向catch發送SIGSEGV信號;你必須建立一個信號處理程序,......呃,在這一點上它會變得棘手,因爲你不清楚你可以在信號處理程序中拋出一個異常。

A throw沒有例外指定rethrows當前異常;它只有在catch塊內纔有意義。

當系統無法進一步擴展堆棧時,您可能會得到SIGSEGV,可能是因爲虛擬內存不足。這意味着你的一個函數調用失敗了,因爲沒有空間來放置它的參數或局部變量或返回地址等。沒有乾淨的方法可以從中恢復,這就是系統產生分段錯誤的原因。

如果故障是因爲calloc()無法分配內存,您不會得到分段錯誤;你會得到一個零回報值。當它發生時,你可以乾淨地同步地提出'內存不足'異常。但那不是你的問題。

+0

事情發生在SIGSEGV之後,我幾乎沒有其他的選擇可以退出程序。我可以爲此寫一個信號處理程序,但它不像我可以打印消息或任何東西。 – ASLilly

+2

正確的 - 所以你不寫一個程序,它不會去得到SIGSEGV信號。它表明有些事情發生了可怕的錯誤。不是一點點小錯誤;致命的錯誤。當'calloc()'失敗時,你不會得到一個SIGSEGV;你得到0回報。你可以在那個時候乾淨地提出一個'內存不足'的例外。 –

+0

+1:試圖澄清信號/異常混淆。 – AAT

1

不能從中恢復,因爲一旦發生故障,程序就不再處於定義良好的狀態,並且也沒有機制回滾到定義良好的狀態。

分段錯誤總是以某種方式出現編程錯誤,您必須簡單地避免它。在C++中,你可以簡單地捕捉異常,從動態分配來:

T * p; 
try { p = new T; } 
catch(const std::bad_alloc & e) { /* ... */ } 

通常沒有必要是相當的手動,不過,因爲你想包適合管理容器(如unique_ptrshared_ptr)內動態分配,並且你應該在你的程序流中的點處捕獲異常(甚至不僅僅是分配),你可以處理錯誤並繼續有意義的。 (感謝例外情況,您通常不需要檢查可能在調用方拋出函數的結果 - 這就是使用異常的全部要點。)


如果由於某種原因,你只是想分配原始內存,無需構建任何對象,你可以做到這一點有兩種方式:

// Method #1, the C++ way: 
void * addr = ::operator new(n); // will throw std::bad_alloc on error 

// Method #2, the manual way: 
void * addr = std::malloc(n); 
if (!addr) throw std::bad_alloc(); // throw exception manually, handled elsewhere 
+0

是的,我喜歡這個我怎麼把它應用到我的代碼上面? – ASLilly

+0

您只需將您的整個函數調用封裝在try塊中 - 但只能在您的程序流程中的某個點實際響應錯誤條件。如果您只是要傳播錯誤,那麼捕獲異常沒有意義。 –