C++中智能指針unique_ptr的實(shí)現(xiàn)詳解
前言
智能指針本質(zhì)上并不神秘,其實(shí)就是 RAII 資源管理功能的自然展現(xiàn)而已。本文將介紹如何實(shí)現(xiàn) C++中智能指針的 unique_ptr。
實(shí)現(xiàn)過程
首先,unique_ptr 能夠包裝任意類型,所以,要讓這個(gè)類能夠包裝任意類型的指針,我們需要把它變成一個(gè)類模板。
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_;
};
目前這個(gè) unique_ptr 的行為還是和指針有點(diǎn)差異的:
- 它不能用
*運(yùn)算符解引用 - 它不能用
->運(yùn)算符指向?qū)ο蟪蓡T - 它不能像指針一樣用在布爾表達(dá)式里
不過,這些問題也相當(dāng)容易解決,加幾個(gè)成員函數(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)造和賦值
最簡(jiǎn)單的情況顯然是禁止拷貝。我們可以使用下面的代碼:
template <typename T>
class unique_ptr {
…
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
…
};
禁用這兩個(gè)函數(shù)非常簡(jiǎn)單,但是,有時(shí)我們需要轉(zhuǎn)移所有權(quán),那么這個(gè)方案就不可行了。
這里,我們采用移動(dòng)語(yǔ)義:
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)在它成了移動(dòng)構(gòu)造函數(shù)。 - 把賦值函數(shù)中的參數(shù)類型
unique_ptr&改成了unique_ptr,在構(gòu)造參數(shù)時(shí)直接生成新的智能指針,從而不再需要在函數(shù)體中構(gòu)造臨時(shí)對(duì)象。現(xiàn)在賦值函數(shù)的行為是移動(dòng)還是拷貝,完全依賴于構(gòu)造參數(shù)時(shí)走的是移動(dòng)構(gòu)造還是拷貝構(gòu)造。 根據(jù) C++ 的規(guī)則,如果我提供了移動(dòng)構(gòu)造函數(shù)而沒有手動(dòng)提供拷貝構(gòu)造函數(shù),那后者自動(dòng)被禁用。
子類指針向基類指針的轉(zhuǎn)換
一個(gè) circle* 類是可以隱式轉(zhuǎn)換成 shape* 類的,但上面的 unique_ptr<circle> 卻無(wú)法自動(dòng)轉(zhuǎn)換成 unique_ptr<shape>。
不過,只需要額外加一點(diǎn)模板代碼,就能實(shí)現(xiàn)這一行為。在我們目前給出的實(shí)現(xiàn)里,只需要增加一個(gè)構(gòu)造函數(shù)即可。
template <typename U>
unique_ptr(unique_ptr<U>&& other)
{
ptr_ = other.release();
}
這樣,我們自然而然利用了指針的轉(zhuǎn)換特性:現(xiàn)在 unique_ptr<circle> 可以移動(dòng)給 unique_ptr<shape>,但不能移動(dòng)給 unique_ptr<triangle>。不正確的轉(zhuǎn)換會(huì)在代碼編譯時(shí)直接報(bào)錯(cuò)。
驗(yàn)證
unique_ptr<shape> ptr1{create_shape(shape_type::circle)};
unique_ptr<shape> ptr2{ptr1}; // 編譯出錯(cuò)
unique_ptr<shape> ptr3;
ptr3 = ptr1; // 編譯出錯(cuò)
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)一個(gè) unique_ptr 相對(duì)比較簡(jiǎn)單,因?yàn)椴簧婕耙糜?jì)數(shù),只需要一個(gè)對(duì)象只能被單個(gè) unique_ptr 所擁有。
以上就是C++中智能指針unique_ptr的實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于C++智能指針unique_ptr的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c++項(xiàng)目中后綴名vcxproj和sln的區(qū)別及說(shuō)明
這篇文章主要介紹了c++項(xiàng)目中后綴名vcxproj和sln的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
CRC校驗(yàn)原理及其C語(yǔ)言實(shí)現(xiàn)詳解
循環(huán)冗余校驗(yàn)(Cyclic?Redundancy?Check,?CRC)是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或計(jì)算機(jī)文件等數(shù)據(jù)產(chǎn)生簡(jiǎn)短固定位數(shù)校驗(yàn)碼的一種信道編碼技術(shù)。本文主要介紹了CRC校驗(yàn)原理及其C語(yǔ)言實(shí)現(xiàn),感興趣的可以了解一下2023-03-03
C語(yǔ)言詳解strcmp函數(shù)的分析及實(shí)現(xiàn)
strcmp函數(shù)語(yǔ)法為“int strcmp(char *str1,char *str2)”,其作用是比較字符串str1和str2是否相同,如果相同則返回0,如果不同,前者大于后者則返回1,否則返回-12022-05-05
C語(yǔ)言編程數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)詳解小白篇
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ),非常適合初學(xué)數(shù)據(jù)結(jié)構(gòu)的小白,有需要的朋友可以借鑒參考下,希望可以有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-09-09

