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

創(chuàng)新互聯(lián)公司長期為超過千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為洮南企業(yè)提供專業(yè)的網(wǎng)站設(shè)計、成都做網(wǎng)站,洮南網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
最近,我寫了一個簡單的shared_ptr,在這里分享一波。
首先定義一個主管引用計數(shù)的類:
class SharedCount {
public:
SharedCount() : count_{1} {}
void add() { ++count_; }
void minus() { --count_; }
int get() const { return count_; }
private:
std::atomic count_;
};
然后就是SharedPtr類,首先在構(gòu)造函數(shù)中創(chuàng)建SharedCount的對象:
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_;
};
通過構(gòu)造函數(shù)創(chuàng)建出來的SharedPtr引用計數(shù)肯定是1,那析構(gòu)函數(shù)怎么實現(xiàn)?無非就是將引用計數(shù)減1,如果引用計數(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)造和拷貝賦值的時候?qū)⒁糜嫈?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;
}
};
處理了拷貝語義,還需要處理移動語義,即實現(xiàn)移動構(gòu)造和移動賦值函數(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;
}
};
在移動語義中,引用計數(shù)保持不變,同時清空原參數(shù)中的指針。
關(guān)于共享指針,到這里基本邏輯都已經(jīng)實現(xiàn)完成,但還需要補充獲取裸指針、獲取引用計數(shù)等接口:
這樣一個完整的智能指針大體已經(jīng)實現(xià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完成后,再來寫點有意思的,不知道大家有沒有用過這幾個指針轉(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完成后,再來寫點有意思的,不知道大家有沒有用過這幾個指針轉(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)知道這幾個函數(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;
};
上面的代碼還是有問題,因為SharedPtr(const SharedPtr& p, T* ptr)是private,static_pointer_cast無法訪問,有兩種辦法,一是變成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);
}
再測試一下:
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()
上面只實現(xiàn)了static_pointer_cast,其他xxx_pointer_cast的原理類似,大家應(yīng)該也明白了吧。
C++還有個unique_ptr,這個相對于shared_ptr就簡單多了,表示unique語義,沒有引用計數(shù)的概念,因為不允許拷貝,原理就是禁止調(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_;
};
重點其實只有這兩個delete:
template
class UniquePtr {
public:
UniquePtr(const UniquePtr& p) = delete;
UniquePtr& operator=(const UniquePtr& p) = delete;
};
到這里已經(jīng)實現(xiàn)了一個簡單的shared_ptr和unique_ptr,希望對大家有所幫助,完整代碼見這里:
??https://github.com/chengxumiaodaren/cpp-learning/blob/master/src/test_shared_ptr.cc??
文章題目:手?jǐn)]一個智能指針,你學(xué)會了嗎?
當(dāng)前網(wǎng)址:http://m.5511xx.com/article/ccsohsh.html


咨詢
建站咨詢
