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