【C++】智能指针 Smart Pointer
智能指針
- 智能指針 Smart Pointer
- auto_ptr
- 智能指針的自實現(xiàn)
- shared_ptr
- weak_ptr
- unique_ptr
智能指針 Smart Pointer
用來改善傳統(tǒng)指針的問題
需要手動管理內(nèi)存
容易發(fā)生內(nèi)存泄露(忘記釋放、出現(xiàn)異常等)
比如:
一旦test()拋出異常,p指針的內(nèi)存就不會被釋放,發(fā)生內(nèi)存泄露。
釋放后產(chǎn)生野指針
智能指針就是為了解決傳統(tǒng)指針存在的問題
- auto_prt:屬于C++98標(biāo)準(zhǔn),在C++11已不推薦使用(有缺陷,比如不能用于數(shù)組
- shared_ptr:屬于C++11標(biāo)準(zhǔn)
- unique_ptr:屬于C++11標(biāo)準(zhǔn)
auto_ptr
class Person {int m_age; public:Person() {cout << "Person()" << endl;}Person(int age): m_age(age) {cout << "Person(int)" << endl;}~Person() {cout << "~Person()" << endl;}void run() {cout << "run()" << endl;} };void test() {// 可以理解為:智能指針p指向了堆空間的Person對象auto_ptr<Person> p(new Person(20));p->run(); }int main() {test();getchar();return 0; }// 輸出: // Person(int) // run() // ~Person() // 并沒有調(diào)用析構(gòu)函數(shù),但會自動調(diào)用智能指針不能指向??臻g的對象!因為智能指針是堆空間指針,析構(gòu)時會double free!
{Person person(20); // 創(chuàng)建在棧空間auto_ptr<Person> p(&person); // 堆空間指針指向棧空間對象p->run();// 會調(diào)用兩次析構(gòu)函數(shù) }不能作用于數(shù)組
{auto_ptr<Person> p(new Person[10]); // 一個數(shù)組,里面有10個Person對象p->run(); } // 構(gòu)造函數(shù)會調(diào)用10次,但析構(gòu)函數(shù)只會調(diào)用一次,然后拋出異常可以使用shared_ptr
智能指針的自實現(xiàn)
template <typename T> class SmartPointer { private:T *m_obj; public:SmartPointer(T *obj): m_obj(obj) {}~SmartPointer() {if (m_obj == nullptr) return;delete m_obj;}T *operator->() { // 為了可以使用T類的成員函數(shù)return m_obj;} }; int main() {{SmartPointer<Person> p(new Person(20));p->run();// 看似是一個指針,實則是一個對象,重載了運算符}getchar();return 0; }shared_ptr
-
多個shared_ptr可以指向同一個對象,當(dāng)最后一個shared_ptr在作用于范圍內(nèi)結(jié)束時,對象才會被自動釋放
{shared_ptr<Person> p1(new Person(10));shared_ptr<Person> p2 = p1;shared_ptr<Person> p3 = p2;shared_ptr<Person> p4(p3); // 本質(zhì)上都是p1// 當(dāng)最后一個指針(p4)結(jié)束后,p1才會被自動釋放 }-
可以通過一個已存在的智能指針初始化一個新的智能指針
shared_ptr<Person> p1(new Person()); shared_ptr<Person> p2(p1); -
針對數(shù)組的用法
shared_ptr<Person> ptr1(new Person[5]{}, [](Person *p) { delete[] p;}); // 傳入lambda表達式表明想要怎么析構(gòu)
-
-
shared_ptr的原理
-
一個shared_ptr會對一個對象產(chǎn)生強引用
-
每個對象都有個與之對應(yīng)的強引用計數(shù),記錄著當(dāng)前對象被多少個shared_ptr強引用著
- 可以通過shared_ptr的use_count函數(shù)獲得強引用計數(shù)
- 當(dāng)有一個新的shared_ptr指向?qū)ο髸r,對象的強引用計數(shù)就會+1
- 當(dāng)有一個shared_ptr銷毀時,比如作用域結(jié)束,對象的強引用計數(shù)就會-1
- 當(dāng)一個對象的強引用計數(shù)為0時(沒有任何shared_ptr指向?qū)ο髸r),對象就會自動銷毀(析構(gòu)
-
-
循環(huán)引用
你強引用我,我強引用你,大家都別銷毀
class Person;class Car { public:shared_ptr<Person> m_person;~Car() {cout << "~Car()" << endl;} };class Person { public:shared_ptr<Person> m_car;~Person() {cout << "~Person()" << endl;} };int main() {{shared_ptr<Person> person(new Person());shared_ptr<Car> car(new Car());person->m_car = car;car->m_person = person;// 不會析構(gòu),會造成內(nèi)存泄漏}getchar();return 0; }
Person和Car的強引用計數(shù)都是2
一旦main函數(shù)內(nèi)的大括號結(jié)束,??臻g的person 和car的強引用結(jié)束,但堆空間的person和car相互的強引用并不結(jié)束
所以Person和Car的強引用計數(shù)變?yōu)?,無法銷毀
如何解決呢?
使用弱引用(weak_ptr)
weak_ptr
-
會對一個對象產(chǎn)生弱引用
-
可以指向?qū)ο蠼鉀Qshared_ptr的循環(huán)引用問題
class Person;class Car { public:weak_ptr<Person> m_person;~Car() {cout << "~Car()" << endl;} };class Person { public:shared_ptr<Person> m_car;~Person() {cout << "~Person()" << endl;} };int main() {{shared_ptr<Person> person(new Person());shared_ptr<Car> car(new Car());person->m_car = car;car->m_person = person;// 不會析構(gòu),會造成內(nèi)存泄漏}getchar();return 0; }
當(dāng)??臻g的Person和Car被銷毀后,Person先銷毀,因為Person強引用計數(shù)為0
Person被銷毀后,Car的強引用也為0了,所以Car也會被銷毀
unique_ptr
unique_ptr也會對一個對象產(chǎn)生強引用,它可以確保同一時間只有1個指針指向?qū)ο?/strong>。
int main() {{unique_ptr<Person> p1(new Person());unique_ptr<Person> p2(p1); // 報錯,不能把兩個指針指向同一個對象}getchar();return 0; }- 當(dāng)unique_ptr銷毀時(作用域結(jié)束時),其指向的對象也就自動銷毀了
- 可以使用std::move函數(shù)轉(zhuǎn)移unique_ptr的所有權(quán)
總結(jié)
以上是生活随笔為你收集整理的【C++】智能指针 Smart Pointer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++】静态成员 static
- 下一篇: 【C++】运算符重载 Operator