2013-07-30 134 views

回答

18

讓我們組織一些使用和陷阱使用Q & A格式。


Q1:我想一個指針存儲類ComponentX類中。
我不希望「容器」類X是可複製的; XComponent實例的唯一所有者。
我知道擁有指針是一件壞事和「leaktrocities」的潛在來源(而不是觀察生指針是罰款)。 什麼智能指針我可以用於此目的?

A1: C++ 11的std::unique_ptr無疑是一個不錯的選擇。

唯一(非共享)所有權的情況下沒有問題,也沒有std::shared_ptr的開銷。
這是一個很好的替代以前的C++ 98/03 boost::scoped_ptr
其實,另外,std::unique_ptr提供了移動語義
所以,如果X類包含unique_ptr<Component>數據成員(和其他可移動數據成員),整個類X將自動移動。

一個例子使用的顯示如下:

#include <memory> // for std::unique_ptr 

class X 
{ 
    std::unique_ptr<Component> m_pComponent; 
    .... 

public: 
    X() 
     : m_pComponent(new Component()) 
    { 
     .... 
    } 
} 

(當然,作爲一個智能指針,沒有必要包含類的析構函數顯式刪除)


Q2:太棒了!不需要明確的析構函數,沒有std::shared_ptr開銷(典型的C++哲學:「我們不支付我們不使用的東西」),移動已經實現的語義機器!
但是,我遇到了一個問題:我的類Component有一個構造函數重載,它在創建Component實例之前需要構造函數代碼中需要計算的一些參數。我嘗試使用普通operator=分配新建分配FY在構造函數中分配新創建的Componentunique_ptr,但我得到了一個錯誤信息:

X::X() 
{ 
    .... 

    const int param = CalculateCoolParameter(); 

    // This assignment fails: 
    m_pComponent = new Component(param); // <---- Error pointing to '=' here 
       ^--- error 
} 

A2: OK,也許你曾預計的operator=超載釋放先前擁有 指針(如果有的話)並分配給新創建的一個。
不幸的是,沒有這樣的過載。
但是,std::unique_ptr::reset()方法會做!

m_pComponent.reset(new Component(param)); 

Q3:嘿!這unique_ptr真的很酷! 我喜歡它很聰明,它可以自動移動,並且不會帶來開銷。
所以,我想用它來存儲一個動態分配的數組的一些恆定的大小(在運行時計算),而不是使用std::vector(在這部分代碼中我受到高度約束,而且我不想要支付std:vector的開銷,因爲我不希望動態調整大小特徵,深度複製等等)所有std::vector

我想是這樣的:

const size_t count = GetComponentsCount(); 
unique_ptr<Component> components(new Component[count]); 

它編譯罰款,但我注意到,~Component調用析構函數只一次,而不是我的預期count析構函數調用!這裏有什麼問題?

A3:問題是,使用上述語法,std::unique_ptr使用delete釋放分配的對象。但由於這些分配使用new[],正確的清除呼叫是delete[](不是簡單的delete沒有括號)。

爲了解決這個問題,並指示unique_ptr正確使用delete[]釋放資源,下面的語法必須使用:

unique_ptr<Component[]> components(new Components[count]); 
//     ^^ 
// 
// Note brackets "[]" after the first occurrence of "Component" 
// in unique_ptr template argument. 
// 

Q4:那太好了!但我可以用unique_ptr同樣在沒有使用普通的C++ delete(或delete[]),而是使用一些自定義清理功能進行的資源釋放代碼的情況下,像fclose()對於C <stdio.h>文件(fopen()打開),或CloseHandle()對於Win32文件HANDLE s(使用CreateFile()創建)?

A4:這是絕對有可能:你可以指定一個定製刪除std::unique_ptr

例如:

// 
// Custom deleter function for FILE*: fclose(). 
// 
std::unique_ptr<FILE,   // <-- the wrapped raw pointer type: FILE* 
       int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype 
myFile(fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen() 
     fclose);    // <-- the deleter function: fclose() 



// 
// Custom deleter functor for Win32 HANDLE: calls CloseHandle(). 
// 
struct CloseHandleDeleter 
{ 
    // The following pointer typedef is required, since 
    // the raw resource is HANDLE (not HANDLE*). 
    typedef HANDLE pointer; 

    // Custom deleter: calls CloseHandle(). 
    void operator()(HANDLE handle) const 
    { 
     CloseHandle(handle); 
    } 
}; 

std::unique_ptr<HANDLE, CloseHandleDeleter> myFile(CreateFile(....)); 
+0

FWIW,你支付的矢量功能你不使用什麼? (提示:什麼都沒有) –

+0

至少從內存佔用中,'std :: vector'可以使用3個指針,而不是'unique_ptr'。 –

+0

A2:一個更好的解決方案,如果可能的話,就是有一個方法進行計算並返回std :: unique_ptr,然後在初始化程序列表中使用該權限。 – stijn