C++ smart pointer,unique_ptr,shared_ptr
smart pointer
與一般的pointer相比,smart pointer的優勢在於我們不需要顯式地呼叫delete(ptr)
來釋放它所佔用的記憶體。只要smart pointer一落在可視範圍之外,smart pointer的destructor便會自動地釋放動態分配的內存。
std::unique_ptr
我們可以將std::unique_ptr
看成是raw pointer的container。當我們希望一塊資源只能被一個指標所存取時,我們就可以使用std::unique_ptr
。
C++不允許std::unique_ptr
被複製。所以如果我們想要轉移資源的擁有者,就必須借助std::move
來達成。
如:
//會出錯,不能複製unique_ptr
unique_ptr<A> ptr2 = ptr1;
//可以成功執行
unique_ptr<A> ptr2 = move(ptr1);
在TensorRT/samples/opensource/sampleMNIST/sampleMNIST.cpp
中有下面這麼一段:
template <typename T>
using SampleUniquePtr = std::unique_ptr<T, samplesCommon::InferDeleter>;
template <
class T,
class Deleter
> class unique_ptr<T[], Deleter>;
可以得知samplesCommon::InferDeleter
是這裡指定的deleter,在該unique_ptr
被摧毀或指向別處時,deleter就會負責清理該unique_ptr
所佔用的空間。
Deleter
上面定義的SampleUniquePtr
是這麼被調用的:
SampleUniquePtr<nvcaffeparser1::IBinaryProtoBlob>
mMeanBlob;
其中nvcaffeparser1::IBinaryProtoBlob
來自TensorRT/include/NvCaffeParser.h
:
//!
//! \class IBinaryProtoBlob
//!
//! \brief Object used to store and query data extracted from a binaryproto file using the ICaffeParser.
//!
//! \see nvcaffeparser1::ICaffeParser
//!
//! \warning Do not inherit from this class, as doing so will break forward-compatibility of the API and ABI.
//!
class IBinaryProtoBlob
{
public:
virtual const void* getData() TRTNOEXCEPT = 0;
virtual nvinfer1::DimsNCHW getDimensions() TRTNOEXCEPT = 0;
virtual nvinfer1::DataType getDataType() TRTNOEXCEPT = 0;
virtual void destroy() TRTNOEXCEPT = 0;
protected:
virtual ~IBinaryProtoBlob() {}
};
而samplesCommon::InferDeleter
定義於TensorRT/samples/common/common.h
:
struct InferDeleter
{
template <typename T>
void operator()(T* obj) const
{
if (obj)
{
obj->destroy();
}
}
};
它會調用T
型別(此處即為nvcaffeparser1::IBinaryProtoBlob
)物件的destroy
函數來銷毀該物件。
關於Deleter
:
Deleter must be FunctionObject or lvalue reference to a FunctionObject
or lvalue reference to function, callable with an argument of
type unique_ptr<T, Deleter>::pointer
即Deleter
必須是一個functor,或是functor的左值引用,又或是函數的左值引用。由於InferDeleter
override了()
這個運算子,所以它確實是一個functor。
std::unique_ptr::get
在TensorRT/parsers/caffe/caffeParser/caffeParser.cpp
的函數CaffeParser::parse
中使用了std::unique_ptr::get
的語法:
mModel = std::unique_ptr<trtcaffe::NetParameter>(new trtcaffe::NetParameter);
//bool readBinaryProto(trtcaffe::NetParameter* net, const char* file, size_t bufSize)
/**/readBinaryProto(mModel.get(), modelFile, mProtobufBufferSize))/**/
std::unique_ptr::get
pointer get() const noexcept;
其作用為:
Returns the stored pointer.
即回傳std::unique_ptr
內儲存的指標。
std::shared_ptr
std::shared_ptr
亦是raw pointer的container。當我們希望一塊資源能被多個pointer所存取時,我們就會用到std::shared_ptr
。
C++允許多個shared_ptr
指向同一塊資源。並且shared_ptr
還自帶了計數功能,即,每當一個新的shared_ptr
指向該資源時,reference count就會加一;而每當一個shared_ptr
指向別處或是被銷毀時,reference count就會減一。
TensorRT/samples/opensource/sampleMNIST/sampleMNIST.cpp
中對shared_ptr
的使用:
std::shared_ptr<nvinfer1::ICudaEngine> mEngine{nullptr}; //!< The TensorRT engine used to run the network
//...
mEngine = std::shared_ptr<nvinfer1::ICudaEngine>(
builder->buildEngineWithConfig(*network, *config), samplesCommon::InferDeleter());
以下是shared_pointer的constructor的定義,可與上面的代碼相對照:
template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );