新聞中心
估計(jì)大家面試過(guò)程中應(yīng)該都會(huì)被問(wèn)到C++11的shared_ptr是如何實(shí)現(xiàn)的,大家應(yīng)該都能答出來(lái)引用計(jì)數(shù)的概念,但是如果要讓你手寫(xiě)一個(gè)shared_ptr,你能寫(xiě)出來(lái)嗎?

創(chuàng)新互聯(lián)公司長(zhǎng)期為超過(guò)千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為洮南企業(yè)提供專(zhuān)業(yè)的網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站,洮南網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
最近,我寫(xiě)了一個(gè)簡(jiǎn)單的shared_ptr,在這里分享一波。
首先定義一個(gè)主管引用計(jì)數(shù)的類(lèi):
class SharedCount {
public:
SharedCount() : count_{1} {}
void add() { ++count_; }
void minus() { --count_; }
int get() const { return count_; }
private:
std::atomic count_;
};
然后就是SharedPtr類(lèi),首先在構(gòu)造函數(shù)中創(chuàng)建SharedCount的對(duì)象:
template
class SharedPtr {
public:
SharedPtr(T* ptr) : ptr_{ptr}, ref_count_{new SharedCount} {}
SharedPtr() : ptr_{nullptr}, ref_count_{new SharedCount} {}
private:
T* ptr_;
SharedCount* ref_count_;
};
通過(guò)構(gòu)造函數(shù)創(chuàng)建出來(lái)的SharedPtr引用計(jì)數(shù)肯定是1,那析構(gòu)函數(shù)怎么實(shí)現(xiàn)?無(wú)非就是將引用計(jì)數(shù)減1,如果引用計(jì)數(shù)最終減到0,則釋放所有指針:
template
class SharedPtr {
public:
~SharedPtr() { clean(); }
private:
void clean() {
if (ref_count_) {
ref_count_->minus();
if (ref_count_->get() == 0) {
if (ptr_) delete ptr_;
delete ref_count_;
}
}
}
};
然后就是智能指針的關(guān)鍵部分,即在拷貝構(gòu)造和拷貝賦值的時(shí)候?qū)⒁糜?jì)數(shù)+1:
template
class SharedPtr {
public:
SharedPtr(const SharedPtr& p) {
this->ptr_ = p.ptr_;
this->ref_count_ = p.ref_count_;
ref_count_->add();
}
SharedPtr& operator=(const SharedPtr& p) {
clean();
this->ptr_ = p.ptr_;
this->ref_count_ = p.ref_count_;
ref_count_->add();
return *this;
}
};
處理了拷貝語(yǔ)義,還需要處理移動(dòng)語(yǔ)義,即實(shí)現(xiàn)移動(dòng)構(gòu)造和移動(dòng)賦值函數(shù):
template
class SharedPtr {
public:
SharedPtr(SharedPtr&& p) {
this->ptr_ = p.ptr_;
this->ref_count_ = p.ref_count_;
p.ptr_ = nullptr;
p.ref_count_ = nullptr;
}
SharedPtr& operator=(SharedPtr&& p) {
clean();
this->ptr_ = p.ptr_;
this->ref_count_ = p.ref_count_;
p.ptr_ = nullptr;
p.ref_count_ = nullptr;
return *this;
}
};
在移動(dòng)語(yǔ)義中,引用計(jì)數(shù)保持不變,同時(shí)清空原參數(shù)中的指針。
關(guān)于共享指針,到這里基本邏輯都已經(jīng)實(shí)現(xiàn)完成,但還需要補(bǔ)充獲取裸指針、獲取引用計(jì)數(shù)等接口:
這樣一個(gè)完整的智能指針大體已經(jīng)實(shí)現(xiàn)完成,運(yùn)行一下看看:
struct A { A() { std::cout << "A() \n"; } ~A() { std::cout << "~A() \n"; }};void test_simple_shared() { A* a = new A; SharedPtr ptr(a); { std::cout << ptr.use_count() << std::endl; SharedPtr b = ptr; std::cout << ptr.use_count() << std::endl; SharedPtr c = ptr; std::cout << ptr.use_count() << std::endl; SharedPtr d = std::move(b); std::cout << ptr.use_count() << std::endl; } std::cout << ptr.use_count() << std::endl;}int main() { test_simple_shared(); }
結(jié)果為:
template
class SharedPtr {
public:
int use_count() { return ref_count_->get(); }
T* get() const { return ptr_; }
T* operator->() const { return ptr_; }
T& operator*() const { return *ptr_; }
operator bool() const { return ptr_; }
private:
T* ptr_;
SharedCount* ref_count_;
};
基本的shared_ptr完成后,再來(lái)寫(xiě)點(diǎn)有意思的,不知道大家有沒(méi)有用過(guò)這幾個(gè)指針轉(zhuǎn)換函數(shù):
struct A {
A() { std::cout << "A() \n"; }
~A() { std::cout << "~A() \n"; }
};
void test_simple_shared() {
A* a = new A;
SharedPtr ptr(a);
{
std::cout << ptr.use_count() << std::endl;
SharedPtr b = ptr;
std::cout << ptr.use_count() << std::endl;
SharedPtr c = ptr;
std::cout << ptr.use_count() << std::endl;
SharedPtr d = std::move(b);
std::cout << ptr.use_count() << std::endl;
}
std::cout << ptr.use_count() << std::endl;
}
int main() { test_simple_shared(); }
結(jié)果為:
A()
1
2
3
3
1
~A()
基本的shared_ptr完成后,再來(lái)寫(xiě)點(diǎn)有意思的,不知道大家有沒(méi)有用過(guò)這幾個(gè)指針轉(zhuǎn)換函數(shù):
template
std::shared_ptrstatic_pointer_cast(const std::shared_ptr& r) noexcept;
template
std::shared_ptrconst_pointer_cast(const std::shared_ptr& r) noexcept;
template
std::shared_ptrdynamic_pointer_cast(const std::shared_ptr& r) noexcept;
template
std::shared_ptrreinterpret_pointer_cast(const std::shared_ptr& r) noexcept;
我默認(rèn)大家已經(jīng)知道這幾個(gè)函數(shù)的作用,這里直接研究一下它的實(shí)現(xiàn):
template
class SharedPtr {
public:
private:
template
SharedPtr(const SharedPtr& p, T* ptr) {
this->ptr_ = ptr;
this->ref_count_ = p.ref_count_;
ref_count_->add();
}
T* ptr_;
SharedCount* ref_count_;
};
template
SharedPtrstatic_pointer_cast(const SharedPtr& p) {
T* ptr = static_cast(p.get());
return SharedPtr(p, ptr);
}
SharedPtr
template
class SharedPtr {
public:
template
friend class SharedPtr;
};
上面的代碼還是有問(wèn)題,因?yàn)镾haredPtr(const SharedPtr& p, T* ptr)是private,static_pointer_cast無(wú)法訪問(wèn),有兩種辦法,一是變成public,二是友元,這里還是友元更合理些,添加友元后的代碼如下:
template
class SharedPtr {
public:
template
friend class SharedPtr;
template
friend SharedPtrstatic_pointer_cast(const SharedPtr& p);
private:
template
SharedPtr(const SharedPtr& p, T* ptr) {
this->ptr_ = ptr;
this->ref_count_ = p.ref_count_;
ref_count_->add();
}
T* ptr_;
SharedCount* ref_count_;
};
template
SharedPtrstatic_pointer_cast(const SharedPtr& p) {
T* ptr = static_cast(p.get());
return SharedPtr(p, ptr);
}
再測(cè)試一下:
struct A {
A() { std::cout << "A() \n"; }
~A() { std::cout << "~A() \n"; }
};
struct B : A {
B() { std::cout << "B() \n"; }
~B() { std::cout << "~B() \n"; }
};
void test_cast_shared() {
B* a = new B;
SharedPtr ptr(a);
{
std::cout << ptr.use_count() << std::endl;
SharedPtr b = static_pointer_cast(ptr);
std::cout << ptr.use_count() << std::endl;
SharedPtr c = ptr;
std::cout << ptr.use_count() << std::endl;
SharedPtr d = ptr;
std::cout << ptr.use_count() << std::endl;
}
std::cout << ptr.use_count() << std::endl;
}
int main() { test_cast_shared(); }
結(jié)果為:
A()
B()
1
2
3
4
1
~B()
~A()
上面只實(shí)現(xiàn)了static_pointer_cast,其他xxx_pointer_cast的原理類(lèi)似,大家應(yīng)該也明白了吧。
C++還有個(gè)unique_ptr,這個(gè)相對(duì)于shared_ptr就簡(jiǎn)單多了,表示unique語(yǔ)義,沒(méi)有引用計(jì)數(shù)的概念,因?yàn)椴辉试S拷貝,原理就是禁止調(diào)用拷貝構(gòu)造函數(shù)和拷貝賦值函數(shù),直接貼代碼吧:
template
class UniquePtr {
public:
UniquePtr(T* ptr) : ptr_{ptr} {}
UniquePtr() : ptr_{nullptr} {}
UniquePtr(const UniquePtr& p) = delete;
UniquePtr& operator=(const UniquePtr& p) = delete;
UniquePtr(UniquePtr&& p) {
this->ptr_ = p.ptr_;
p.ptr_ = nullptr;
}
UniquePtr& operator=(UniquePtr&& p) {
clean();
this->ptr_ = p.ptr_;
p.ptr_ = nullptr;
return *this;
}
T* get() const { return ptr_; }
T* operator->() const { return ptr_; }
T& operator*() const { return *ptr_; }
operator bool() const { return ptr_; }
~UniquePtr() { clean(); }
private:
void clean() {
if (ptr_) delete ptr_;
}
T* ptr_;
};
重點(diǎn)其實(shí)只有這兩個(gè)delete:
template
class UniquePtr {
public:
UniquePtr(const UniquePtr& p) = delete;
UniquePtr& operator=(const UniquePtr& p) = delete;
};
到這里已經(jīng)實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的shared_ptr和unique_ptr,希望對(duì)大家有所幫助,完整代碼見(jiàn)這里:
??https://github.com/chengxumiaodaren/cpp-learning/blob/master/src/test_shared_ptr.cc??
新聞標(biāo)題:手?jǐn)]一個(gè)智能指針,你學(xué)會(huì)了嗎?
當(dāng)前鏈接:http://m.fisionsoft.com.cn/article/ccsohsh.html


咨詢(xún)
建站咨詢(xún)
