天天看點

c++11之智能指針

使用c++,除了c++的文法外,指針是我們面臨的最的大一個問題,由于使用不當就會導緻程式意外退出,或着記憶體的占用越來越多,總結起來這些錯誤由以下三個原因造成。

       1 野指針:指針指向的記憶體已經被釋放,但是我們還在使用該指針,或者還在使用之前指向的指針,此時程式會崩潰,也有可能導緻已經釋放的記憶體被重新配置設定給程式使用,造成意想不到的後果。

       2 重複釋放:程式嘗試釋放已經被釋放的記憶體單元,或者釋放已經被重新配置設定過的記憶體單元,會導緻重複釋放錯誤。

       3 記憶體洩漏:不需要的記憶體單元沒有釋放,一旦程式一直在重複這樣的操作,會導緻程式的記憶體占用月來越高。

      雖然顯示的手動管理記憶體,給程式的記憶體管理帶來了很大的自由度,可以高效的利用系統的記憶體,但是也是非常容易出錯的,随着多線程程式的出現和廣泛使用,這樣的問題會更加嚴重,是以c++11通過智能指針來擺脫顯示的記憶體管理,标準庫還實作了‘最小垃圾回收’的支援。

如果你想學習c/c++可以來這個群,首先是三三零,中間是八五九,最後是七六六,裡面有大量的學習資料可以下載下傳。

      c++11中通過unique_ptr,shared_ptr和weak_ptr等智能指針來實作自動釋放堆記憶體。

#include <memory>

#include <iostream>

using namespace std;

struct test{

int a;

};

class demo {

public:

demo() {

b = new test();

std::cout << "demo ()" << std::endl;

}

~demo() {

std::cout << "~demo ()" << std::endl;

void say() {

std::cout << "dem::say()==>" << b->a << std::endl;

test *b;

int main()

{

std::cout << "////////////////unique_ptr///////////////////////" << std::endl;

////////////////unique_ptr///////////////////////

unique_ptr<demo> unique_ptr_demo1(new demo);

unique_ptr_demo1->say();

// unique_ptr<demo> unique_ptr_demo2 = unique_ptr_demo1; //無法通過編譯

demo demo2 = *unique_ptr_demo1;

unique_ptr<demo> unique_ptr_demo3 = move(unique_ptr_demo1);

unique_ptr_demo3->say();

// demo demo5 = *unique_ptr_demo1; //運作時錯誤

//

////////////////shared_ptr///////////////////////

std::cout << "////////////////shared_ptr///////////////////////" << std::endl;

shared_ptr<demo> shared_ptr_demo1(new demo());

shared_ptr_demo1->say();

// shared_ptr_demo1.reset();

shared_ptr<demo> shared_ptr_demo2 = shared_ptr_demo1;

shared_ptr_demo1.reset();

// shared_ptr_demo2.reset(); //運作時錯誤2

shared_ptr_demo2->say();

return 0;

c++11之智能指針

        這裡我們可以看到不用我們手動釋放指針指向的記憶體,編譯器會幫我們釋放該記憶體,對于析構函數的三次調用,分别對應unique_ptr_demo3,demo2和shared_ptr_demo1.

我們主要看unique_ptr和shared_ptr的差別,unique_ptr跟所指對象的記憶體緊緊的綁定在一起,不和其他的指針共享其指向的記憶體(例子中:無法通過編譯的注釋),也就是說unique_ptr不能指派給别的unique_ptr,更深的講,實際上unique_ptr的拷貝構造函數被删除,是以我們不能指派。但是我們可以通過move語義來竊取unique_ptr的記憶體,但是要注意注釋:運作時錯誤,我們竊取了記憶體後,該指針就不能在使用了,因為他指向的記憶體已經被偷走了,特别是當它的成員變量中有指針時,會造成程式崩潰。

       shared_ptr可以指派,允許多個shared_ptr共享一塊記憶體,它采用了引用計數的記憶體管理方式,是以當它放棄了所有權時并不會釋放記憶體,不回影響其他引用這塊記憶體的指針,隻有當引用計數變為0時才會釋放記憶體。我們可以看到例子中 shared_ptr_demo1.reset();并沒有影響shared_ptr_demo2(注:shared_ptr_demo1.reset的注釋此處會徹底釋放記憶體,shared_ptr_demo2會成為一個空指針)是以當我們通過reset顯示的來銷毀指針時,當引用計數沒有為0時隻是把指針設定成nullptr而已。是以既然編輯器會幫我們管理記憶體,如果不是特殊需求,就不要去顯示的調用reset函數來釋放銷毀指針。

class demo{

std::cout << "demo" << std::endl;

template <class t>

void checkptrisvalid(weak_ptr<t>& temp) {

shared_ptr<t> demo = temp.lock();

if (demo != nullptr) {

std::cout << "ptr is good" << std::endl;

}else{

std::cout << "ptr is null" << std::endl;

weak_ptr<demo> weak_ptr_demo1 = shared_ptr_demo1;

checkptrisvalid(weak_ptr_demo1);

shared_ptr_demo2.reset();

c++11之智能指針

     最後說道weak_ptr,它的作用不同于以上兩種,官方說法是它可以指向shared_ptr指向的記憶體,但不擁有該記憶體,當調用lock時可以傳回指向記憶體的shared_ptr,上面的例子中有一個檢查指針是否有效的函數,我們可以看到當我們兩次調用reset釋放指針使得記憶體引用計數變為0,釋放記憶體。這裡是2次,而不是三次就非常明确的證明了,weak_ptr并沒有增加引用計數,也就是說并沒有擁有該記憶體。

說到這裡,我們也應該感覺到我們使用最多的應該是shared_ptr了,隻有在我們需要一個指針獨占一塊記憶體是才會用到unique _ptr,而weak_ptr在必要的時候可以用來監測shared_ptr指向的記憶體是否有效,這是一個非常重要且有意義的用法。

繼續閱讀