C++中智能指針unique_ptr的實(shí)現(xiàn)詳解
前言
智能指針本質(zhì)上并不神秘,其實(shí)就是 RAII 資源管理功能的自然展現(xiàn)而已。本文將介紹如何實(shí)現(xiàn) C++中智能指針的 unique_ptr。
實(shí)現(xiàn)過程
首先,unique_ptr 能夠包裝任意類型,所以,要讓這個類能夠包裝任意類型的指針,我們需要把它變成一個類模板。
template <typename T> class unique_ptr { public: explicit unique_ptr(T* ptr = nullptr) : ptr_(ptr) {} ~unique_ptr() { delete ptr_; } T* get() const { return ptr_; } private: T* ptr_; };
目前這個 unique_ptr
的行為還是和指針有點(diǎn)差異的:
- 它不能用
*
運(yùn)算符解引用 - 它不能用
->
運(yùn)算符指向?qū)ο蟪蓡T - 它不能像指針一樣用在布爾表達(dá)式里
不過,這些問題也相當(dāng)容易解決,加幾個成員函數(shù)就可以:
template <typename T> class unique_ptr { public: … T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } operator bool() const { return ptr_; } }
拷貝構(gòu)造和賦值
最簡單的情況顯然是禁止拷貝。我們可以使用下面的代碼:
template <typename T> class unique_ptr { … unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; … };
禁用這兩個函數(shù)非常簡單,但是,有時我們需要轉(zhuǎn)移所有權(quán),那么這個方案就不可行了。
這里,我們采用移動語義:
template <typename T> class unique_ptr { … unique_ptr(unique_ptr&& other) { ptr_ = other.release(); } unique_ptr& operator=(unique_ptr rhs) { rhs.swap(*this); return *this; } … };
- 把拷貝構(gòu)造函數(shù)中的參數(shù)類型
unique_ptr&
改成了unique_ptr&&
;現(xiàn)在它成了移動構(gòu)造函數(shù)。 - 把賦值函數(shù)中的參數(shù)類型
unique_ptr&
改成了unique_ptr
,在構(gòu)造參數(shù)時直接生成新的智能指針,從而不再需要在函數(shù)體中構(gòu)造臨時對象?,F(xiàn)在賦值函數(shù)的行為是移動還是拷貝,完全依賴于構(gòu)造參數(shù)時走的是移動構(gòu)造還是拷貝構(gòu)造。 根據(jù) C++ 的規(guī)則,如果我提供了移動構(gòu)造函數(shù)而沒有手動提供拷貝構(gòu)造函數(shù),那后者自動被禁用。
子類指針向基類指針的轉(zhuǎn)換
一個 circle*
類是可以隱式轉(zhuǎn)換成 shape*
類的,但上面的 unique_ptr<circle>
卻無法自動轉(zhuǎn)換成 unique_ptr<shape>
。
不過,只需要額外加一點(diǎn)模板代碼,就能實(shí)現(xiàn)這一行為。在我們目前給出的實(shí)現(xiàn)里,只需要增加一個構(gòu)造函數(shù)即可。
template <typename U> unique_ptr(unique_ptr<U>&& other) { ptr_ = other.release(); }
這樣,我們自然而然利用了指針的轉(zhuǎn)換特性:現(xiàn)在 unique_ptr<circle>
可以移動給 unique_ptr<shape>
,但不能移動給 unique_ptr<triangle>
。不正確的轉(zhuǎn)換會在代碼編譯時直接報(bào)錯。
驗(yàn)證
unique_ptr<shape> ptr1{create_shape(shape_type::circle)}; unique_ptr<shape> ptr2{ptr1}; // 編譯出錯 unique_ptr<shape> ptr3; ptr3 = ptr1; // 編譯出錯 ptr3 = std::move(ptr1); // OK,可以 unique_ptr<shape> ptr4{std::move(ptr3)}; // OK,可以
完整代碼
#include <utility> template <typename T> class unique_ptr { public: explicit unique_ptr(T* ptr = nullptr) : ptr_(ptr) {} ~unique_ptr() { delete ptr_; } unique_ptr(unique_ptr&& other) { ptr_ = other.release(); } // 子類指針向基類指針的轉(zhuǎn)換 template <typename U> unique_ptr(unique_ptr<U>&& other) { ptr_ = other.release(); } unique_ptr& operator=(unique_ptr rhs) { rhs.swap(*this); return *this; } T* release() { T* ptr = ptr_; ptr_ = nullptr; return ptr; } void swap(unique_ptr& rhs) { using std::swap; swap(ptr_, rhs.ptr_); } T* get() const { return ptr_; } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } operator bool() const { return ptr_; } private: T* ptr_; };
總結(jié)
自行實(shí)現(xiàn)一個 unique_ptr 相對比較簡單,因?yàn)椴簧婕耙糜?jì)數(shù),只需要一個對象只能被單個 unique_ptr
所擁有。
以上就是C++中智能指針unique_ptr的實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于C++智能指針unique_ptr的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于C++浮點(diǎn)數(shù)(float、double)類型數(shù)據(jù)比較與轉(zhuǎn)換的詳解
本篇文章是對C++中浮點(diǎn)數(shù)(float、double)類型數(shù)據(jù)比較與轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05淺談十進(jìn)制小數(shù)和二進(jìn)制小數(shù)之間的轉(zhuǎn)換
下面小編就為大家?guī)硪黄獪\談十進(jìn)制小數(shù)和二進(jìn)制小數(shù)之間的轉(zhuǎn)換。小編覺得挺不錯的現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01C++實(shí)現(xiàn)地鐵自動售票系統(tǒng)程序設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)地鐵自動售票系統(tǒng)程序設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03