1.智能指針的作用
C++程序設計中需要頻繁地動態分配堆內存,堆內存的申請和釋放都由程序員管理。程序員管理堆內存提高了程序的效率,但是整體來說堆內存的管理非常麻煩,且容易造成動態分配的堆內存沒有正確釋放或無法釋放,導致資源浪費,程序運行速度變慢等問題。為了解決這些問題C++11提出了智能指針的概念,方便管理內存。
使用普通指針容易造成內存泄漏、二次釋放、程序發生異常時內存泄漏等問題,使用智能指針可以更好地管理堆內存。
理解智能指針從以下三個方面入手:
1.智能指針是利用了一種叫做RAII(資源分配即初始化)的概念堆普通指針進行封裝,這使得智能指針實質上是一個類對象,但表現得卻像一個指針。
2.智能指針的作用是防止調用delete釋放內存或者程序異常進入catch塊忘記釋放內存,同時多次釋放同一指針會導致程序崩潰。
3.智能指針可以把值語義轉換成引用語義,C++和Java有一處最大的區別在於語義不同,在Java里面下列代碼:
Animal a = new Animal();
Animal b = a;
你當然知道,這里其實只生成了一個對象,a和b僅僅是把持對象的引用而已。但在C++中不是這樣,
Animal a;
Animal b = a;
這里卻是就是生成了兩個對象。
二:智能指針的使用
智能指針在C++11后提供,包含在頭文件<memory>中,shared_ptr,unique_ptr,weak_ptr
2.1shared_ptr的使用:
shared_ptr多個指針指向相同的對象,shared_ptr使用引用計數,每一個shared_ptr的拷貝都指向相同的內存,每使用它一次,內部的引用計數加一,每析構一次,內部的引用計數減1,減為0時,自動釋放所指向的堆內存。shared_ptr內部的引用計數是線程安全的,但是對象的讀取需要加鎖。
- 初始化:智能指針是一個模板類,可以指定類型,傳入指針通過構造函數初始化。也可以使用make_shared函數初始化。不能將指針直接復制給一個智能指針,因為一個是類,一個是指針
- 拷貝和賦值。拷貝使得對象的引用計數加1,賦值使得原對象的引用計數減一,當引用計數為0時,自動釋放內存。后來指向的對象的引用計數加1,指向后來的對象
- get函數獲取原始指針
- 不要用一個原始指針初始化多個shared_ptr,會造成二次釋放同一內存。
#include <iostream> #include<memory> using namespace std; int main() { int a = 1; shared_ptr<int>ptr1 = make_shared<int>(a); shared_ptr<int>ptr2(ptr1);//copy cout << ptr1.use_count() << endl; cout << ptr2.use_count() << endl; int b = 20; int* pb = &a; //shared_ptr<int>ptrb = pb;//error不允許直接將指針賦值給類 shared_ptr<int>ptrb = make_shared<int>(b); ptr2 = ptrb;//賦值 cout << ptr1.use_count() << endl; cout << ptrb.use_count() << endl;
pb = ptrb.get();//獲取原始指針 system("pause"); return 0; }2.2 unique_ptr的使用
unique_ptr唯一擁有其所指對象,同一時刻只有一個unique_ptr指向給定對象(禁止賦值和拷貝,直接賦值會編譯出錯,只有通過移動語義來實現)。unique_ptr指針的生命周期:從unique_ptr創建開始,直到離開作用域。離開作用域時,若其指向對象,則將其所指向對象銷毀(默認使用delete操作符)。unique_ptr指針其所指對象的關系:在智能指針生命周期內,可以改變智能指針所指對象,如創建智能指針時通過構造函數指定、通過reset方法重新指定、通過release方法釋放所有權、通過移動語義轉移所有權。
int main() { unique_ptr<int>uptr(new int(10));//傳入指針,調用構造函數 //unique_ptr<int>uptr2 = uptr;//不能賦值 //unique_ptr<int>uptr3 (uptr);//不能拷貝 unique_ptr<int>uptr3 = move(uptr);//轉移所有權,移動語義 }
2.3 weak_ptr的使用
weak_ptr是為了配合shared_ptr而引入的一種智能指針,因為它不具備普通指針的行為,沒有重載operator*和->,它最大作用在於協助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。weak_ptr可以從一個shared_ptr或者另一個weak_ptr構造,獲得資源的觀測勸,不增加引用計數,沒有共享資源。使用weak_ptr的成員函數use_count()可以觀測資源的引用計數,另一個成員函數expired()的功能等價於use_count=0,但更快,表示被觀測的資源(shared_ptr管理的資源)已經不存在了。weak_ptr可以用lock()從被觀測的shared_ptr獲得一個可用的shared_ptr對象,從而操作資源。當expired()==true時,lock函數將返回一個存儲空指針的shared_ptr。
int main() { { std::shared_ptr<int> sh_ptr = std::make_shared<int>(10); std::cout << sh_ptr.use_count() << std::endl; std::weak_ptr<int> wp(sh_ptr); std::cout << wp.use_count() << std::endl; if (!wp.expired()) { std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr,增加了引用計數 *sh_ptr = 100; std::cout << wp.use_count() << std::endl; std::cout << sh_ptr.use_count() << std::endl; } } //delete memory system("pause"); return 0; }
三:智能指針的實現