2012-03-13 78 views
2

我想通過一個例子,更好地理解如何用我的類實現RAII習語:推薦的方法是什麼確保指針在我的類中正確free?RAII - 類指針和範圍

我有一個課程應該存在的課程。本着RAII的精神,因爲我需要將對此類的引用傳遞給其他類,所以我將它保存在shared_ptr中(不確定它實際上是否需要保存在shared_ptr中,但爲了好玩,它是)。在類ctor中,我使用2個緩衝區(指針),然後多次循環malloc(),使用緩衝區,然後使用free()'ing。在發生事故時,應該包含故障安全代碼以釋放緩衝區。

dtor可以看到緩衝區的唯一方法是如果我將它們聲明爲類變量,但它們只用於類ctor。

例子:

class Input 
{ 
private: 
    PSOMETYPE buffer1; 
public: 
    Input(); 
    ~Input(); 
} 

Input::Input() : buffer1(NULL) 
{ 
    for(blahblah) 
    { 
     buffer1 = (PSOMETYPE)malloc(sizeof(SOMETYPE)); 
     // Do work w/buffer1 
     if(buffer1 != NULL) { free(buffer1); buffer1 = NULL } 
    } 
} 

Input::~Input() 
{ 
    if(buffer1 != NULL) { free(buffer1); buffer1 = NULL } 
} 

考慮我只使用緩衝區的構造函數,是否有意義將其聲明爲私有類變量?如果我宣佈它在Ctor的範圍內,Dtor將不知道它是免費的。

我知道這是一個微不足道的例子,老實說,我可以實現這一點,因爲很容易忘記使用智能指針來引用我的類,並有一個空白的dtor,只是free()'ing,因爲我在循環內。我沒有導師或學校教育,我不確定何時應該遵循RAII成語。

+3

這是一個C和C++想法的奇怪混合......你有使用malloc而不是新的,甚至更好的STL模板容器的原因嗎?這些與RAII概念更適合: – tmpearce 2012-03-13 16:25:00

+0

@tmpearce:這是由於我缺乏經驗,並且使用MSDN作爲學習資源。我讚賞替代品/改進的參考。 – Lokked 2012-03-13 16:53:25

回答

6

RAII的精神是使用本地對象來管理本地分配的對象,而不是它的生命週期人爲地捆綁對象正在構建:

class Input 
{ 
    // no pointer at all, if it's only needed in the constructor 
public: 
    Input(); 
    // no explicit destructor, since there's nothing to explicitly destroy 
}; 

Input::Input() 
{ 
    for(blahblah) 
    { 
     std::unique_ptr<SOMETYPE> buffer1(new SOMETYPE); 

     // or, unless SOMETYPE is huge, create a local object instead: 
     SOMETYPE buffer1; 

     // Do work w/buffer1 
    } // memory released automatically here 
} 

你應該永遠只能有使用delete(或者free,或者其他什麼),如果你正在編寫一個以管理資源爲目的的類 - 而且通常已經有一個標準類(如智能指針或容器)可以做你想做的事情。

當你需要編寫自己的管理類,永遠記得Rule of Three:如果你的析構函數刪除的東西,那麼這個類的默認複製行爲將幾乎肯定會導致重複刪除,所以你需要聲明一個拷貝構造函數和複製分配操作員來防止這種情況。例如,你的類我可以寫下面的不正確的代碼:

{ 
    Input i1;  // allocates a buffer, holds a pointer to it 
    Input i2(i1); // copies the pointer to the same buffer 
}     // BOOM! destroys both objects, freeing the buffer twice 

防止這種情況是要刪除的複製操作最簡單的方法,讓這樣的代碼將無法編譯:

class Input { 
    Input(Input const&) = delete; // no copy constructor 
    void operator=(Input) = delete; // no copy assignment 
}; 

舊的編譯器可能不支持= delete;在這種情況下,您可以通過私下聲明而不用= delete獲得幾乎相同的效果,而不是實施它們。

+0

謝謝。這對我有意義。你的第一句話總結得很完美。在你的代碼不正確的例子中,由於複製unique_ptr會引發異常嗎?我肯定需要實現copy ctor和copy-assignment操作符。再次感謝! – Lokked 2012-03-13 16:41:42

+0

@Lokked:如果這個類包含一個'unique_ptr',那麼如果你試圖複製它,你會得到一個編譯器錯誤。你可以使用'shared_ptr'來獲得安全的指針複製,或者嵌入一個對象而不是指針來獲得對象的複製。在我的例子中,'unique_ptr'根本不是成員,因爲它只在構造函數中需要。 – 2012-03-13 16:44:52