9.C++弱引用智能指针weak_ptr的用处
weak_ptr也是一個引用計數型智能指針,但是它不增加對象的引用計數,即弱引用。與之相對,shared_ptr是強引用,只要有一個指向對象的shared_ptr存在,該對象就不會析構,直到指向對象的最后一個shared_ptr析構或reset()時才會被銷毀。
利用weak_ptr,我們可以解決常見的空懸指針問題以及循環引用問題。
主要是利用了weak_ptr的lock()實現指針的提升!
空懸指針問題
什么是空懸指針?考慮以下這種情況:
有兩個指針p1和p2,指向堆上的同一個對象Object,p1和p2位于不同的線程中。假設線程A通過p1指針將對象銷毀了(盡管把p1置為了NULL),那p2就成了空懸指針。這是一種典型的C/C++內存錯誤。
使用weak_ptr能夠幫我們輕松解決上述的空懸指針問題。
weak_ptr不控制對象的生命期,但是它知道對象是否還活著。如果對象還活著,那么它可以提升為有效的shared_ptr(提升操作通過lock()函數獲取所管理對象的強引用指針);如果對象已經死了,提升會失敗,返回一個空的shared_ptr。示例代碼如下:
#include <iostream> #include <memory>int main() {// OLD, problem with dangling pointer// PROBLEM: ref will point to undefined data!int* ptr = new int(10);int* ref = ptr;delete ptr;// NEW// SOLUTION: check expired() or lock() to determine if pointer is valid// empty definitionstd::shared_ptr<int> sptr;// takes ownership of pointersptr.reset(new int);*sptr = 10;// get pointer to data without taking ownershipstd::weak_ptr<int> weak1 = sptr;// deletes managed object, acquires new pointersptr.reset(new int);*sptr = 5;// get pointer to new data without taking ownershipstd::weak_ptr<int> weak2 = sptr;// weak1 is expired!if(auto tmp = weak1.lock())std::cout << *tmp << '\n';elsestd::cout << "weak1 is expired\n";// weak2 points to new data (5)if(auto tmp = weak2.lock())std::cout << *tmp << '\n';elsestd::cout << "weak2 is expired\n"; }循環引用問題
一種循環引用的情況如下:
#include <iostream> #include <memory>using namespace std;class Parent; class Child; typedef shared_ptr<Parent> parent_ptr; typedef shared_ptr<Child> child_ptr; class Parent { public:~Parent() { cout << "~Parent()" << endl; } public:child_ptr children; };class Child { public:~Child() { cout << "~Child()" << endl; } public:parent_ptr parent; };int main() {parent_ptr father(new Parent);child_ptr son(new Child);// 父子互相引用father->children = son;son->parent = father;cout << father.use_count() << endl; // 引用計數為2cout << son.use_count() << endl; // 引用計數為2return 0; }如上代碼,將在程序退出前,father的引用計數為2,son的計數也為2,退出時,shared_ptr所作操作就是簡單的將計數減1,如果為0則釋放,顯然,這個情況下,引用計數不為0,于是造成father和son所指向的內存得不到釋放,導致內存泄露。
使用weak_ptr可以打破這樣的循環引用。由于弱引用不更改引用計數,類似普通指針,只要把循環引用的一方使用弱引用,即可解除循環引用。
以上述代碼為例,只要把Child類的代碼修改為如下即可:
class Child { public:~Child() { cout << "~Child()" << endl; } public:weak_ptr<Parent> parent; };最后值得一提的是,雖然通過弱引用指針可以有效的解除循環引用,但這種方式必須在能預見會出現循環引用的情況下才能使用,即這個僅僅是一種編譯期的解決方案,如果程序在運行過程中出現了循環引用,還是會造成內存泄漏的。因此,不要認為只要使用了智能指針便能杜絕內存泄漏。
所以引用計數的方式還是會有內存泄漏的風險
?
總結
以上是生活随笔為你收集整理的9.C++弱引用智能指针weak_ptr的用处的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8.公有继承 保护继承 私有继承
- 下一篇: 12.Linux:exec函数族