2013-12-15 96 views
0

在最新的C++編程語言書中,Bjarne提出了一種正統錯誤處理的替代方案,即使用異常。這是章13.3.1,他寫道:內存管理策略問題

void test() 
    // handle undiciplined resource acquisition 
    // demonstrate that arbitrary actions are possible 
{ 
    int* p = new int{7};        // probably should use a unique_ptr (§5.2) 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

    auto act1 = finally([&]{ delete p; 
           free(buf);    // C-style deallocation 
           cout<< "Goodby, Cruel world!\n"; 
          } 
        ); 

    int var = 0; 
    cout << "var = " << var << '\n'; 

    // nested block: 
    { 
      var = 1; 
      auto act2 = finally([&]{ cout<< "finally!\n"; var=7; }); 
      cout << "var = " << var << '\n'; 
    } // act2 is invoked here 

    cout << "var = " << var << '\n'; 
}// act1 is invoked here 

雖然我明白他試圖解釋,什麼該代碼應該實現的,我有問題,認爲這片段是免費韭菜:

> 1. int* p = new int{7};        // probably should use a unique_ptr (§5.2) 
> 2.   int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 
>   
>  
> 3.   auto act1 = finally([&]{ delete p; 
>           free(buf);    // C-style deallocation 
>           cout<< "Goodby, Cruel world!\n"; 
>         } 
>        ); 

爲什麼? 因爲如果在第二行(2)我們得到異常拋出(假設沒有調用一個malloc而是一個可以實際拋出的函數,因爲我相信Bjarne試圖解釋的概念是使用finally構造這裏的malloc調用是不相關的,偶然的,可以被任何調用取代),那麼如果兩個拋出然後3永遠不會到達,我們有資源韭菜從1 我是否正確?

+1

如果這就像一個的malloc函數拋出一個異常,但這樣做之前,所以分配一些內存它不那麼自由,那麼它是非常很調皮。爲什麼要承擔這樣的事情?沒人理智會寫,imo。如果它拋出異常,沒有人會知道你將不得不釋放的內存地址。 – polkadotcadaver

+0

儘管如此,如果在內存分配和「finally」對象創建之間引發異常時忽略這一點,那麼會出現泄漏。 – polkadotcadaver

+0

@polkadotcadaver:泄漏不會出現在* buf中,而是出現在* p中。 –

回答

1

基本上什麼是在上面的代碼段發生的事情是:

 int* p = new int{7};        // probably should use a unique_ptr 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

分配內存兩者經由C++ newC的malloc。這兩個指針都沒有管理,如果此時有任何代碼被拋出,內存將被泄漏。但是請注意,malloc不會如此孤立地拋出此代碼是安全的。

http://en.cppreference.com/w/cpp/memory/c/malloc

auto act1 = finally([&]{ delete p; 
          free(buf);    // C-style deallocation 
          cout<< "Goodby, Cruel world!\n"; 
         } 
       ); 

在這種代碼的RAII類型是從最後函數返回。當act1被銷燬時(無論是例外情況還是離開此範圍),它將執行可調用參數。

因爲這直接跟在malloc之後我們現在已確保內存不會泄漏。

下面的代碼不過是不安全的:

 int* p = new int{7};        // probably should use a unique_ptr 
    int* buf = (int*)malloc(100*sizeof(int));   // C-style allocation 

    throwing_function(); 

    auto act1 = finally([&]{ delete p; 
          free(buf);    // C-style deallocation 
          cout<< "Goodby, Cruel world!\n"; 
         } 
       ); 

但是Bjarne的評論是現貨上,只需使用一個std::unique_ptr

編輯:

一種利用最後:

database_handle dh1; 
dh1.do("action..."); 
finally([&]{ 
    if(!dh1.success()) { 
     dh1.rollback(); 
    } 
); 
+0

嗨,我的意思是說,如果malloc被其他調用替換(可能會拋出),則會發生泄漏。 – smallB

+0

我的答案中的最後一段代碼涵蓋了這一點。如果有一個函數可以在分配點和'finally'處理函數之間傳遞,那麼是的代碼可能會泄漏。這就是爲什麼最好使用智能指針的原因。 – 111111

+0

這基本上意味着Bjarne解釋的技術僅在沒有任何代碼行的情況下才起作用,但是在最後調用投擲之前的第一行代碼。有點毫無意義,不得不說。 – smallB