什麼是一些C++ 11 std::unique_ptr
使用和陷阱?一些std :: unique_ptr使用和「陷阱」
我還可以使用std::unique_ptr
來存儲動態分配的數組嗎?
我還可以使用std::unique_ptr
還使用自定義刪除機制的資源嗎?
什麼是一些C++ 11 std::unique_ptr
使用和陷阱?一些std :: unique_ptr使用和「陷阱」
我還可以使用std::unique_ptr
來存儲動態分配的數組嗎?
我還可以使用std::unique_ptr
還使用自定義刪除機制的資源嗎?
讓我們組織一些使用和陷阱使用Q & A格式。
Q1:我想一個指針存儲類Component
我X
類中。
我不希望「容器」類X
是可複製的; X
是Component
實例的唯一所有者。
我知道擁有生指針是一件壞事和「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在構造函數中分配新創建的Component
到unique_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(....));
FWIW,你支付的矢量功能你不使用什麼? (提示:什麼都沒有) –
至少從內存佔用中,'std :: vector'可以使用3個指針,而不是'unique_ptr'。 –
A2:一個更好的解決方案,如果可能的話,就是有一個方法進行計算並返回std :: unique_ptr,然後在初始化程序列表中使用該權限。 – stijn