1. 程式人生 > >【C++】智慧指標簡述(四):shared_ptr

【C++】智慧指標簡述(四):shared_ptr

開發十年,就只剩下這套架構體系了! >>>   

  在開始本文內容之前,我們再來總結一下,前文內容:

  1.智慧指標採用RAII機制,在構造物件時進行資源的初始化,析構物件時進行資源的清理及汕尾.

  2.auto_ptr防止拷貝後析構釋放同一塊記憶體,採用"轉移所有權"的方法.(實際開發中auto_ptr並不實用)

  3.scoped_ptr與auto_ptr類似,但是它與auto_ptr最大的區別是:它不能轉移所有權,即就是禁止拷貝/賦值!(當然,我們也探討了C++中禁止拷貝物件的技術,在此不贅述)

  回顧完前文內容後,我們今天來討論shared_ptr.

  我們雖然有了scoped_ptr,但在實際開發過程中,我們的確要是想對智慧指標進行拷貝,那scoped_ptr就鞭長莫及了.

  那麼,我們回到原始的問題:對智慧指標進行拷貝,會出現什麼情況?

  我們在第二篇文章也分析了:如果對智慧指標不進行特殊處理,在析構時,會將同一塊記憶體釋放多次,程式會崩潰!

  因此,我們要想對智慧指標進行拷貝,就必須做一些特殊的處理,使得解構函式只釋放一次記憶體.

  此時,如果探究過深淺拷貝的同學,可能心中已經有了答案:用引用計數!!!(深淺拷貝問題,以後我會討論,不是本文重點)

  考慮到有些童鞋可能不知道什麼是引用計數,那我就在這裡解釋一下:

  在引用計數中,每一個物件負責維護物件所有引用的計數值。當一個新的引用指向物件時,引用計數器就遞增,當去掉一個引用時,引用計數就遞減。當引用計數到零時,該物件就將釋放佔有的資源。——百度百科

  通俗一點的講:在本例中我們通過count變數來記錄當前有多少個物件共同維護著這個指標,每次拷貝/賦值的時候,讓count++.

1

2

3

4

5

6

7

8

//拷貝構造(賦值運算子過載類似,用簡潔寫法呼叫拷貝構造即可)

SharedPtr(const SharedPtr &sp)

    :_ptr(sp._ptr)

    ,_count(sp._count){

        if(_count!=NULL){

            ++(*_count);

        }

}

  當物件析構時,首先我們看count是不是1,如果不是1,說明還有其他物件在維護這個指標,我們讓count--.否則的話,就說明,只有當前物件在維護這個指標,此時就可以愉快的把指標delete掉了.

1

2

3

4

5

6

7

8

9

10

~SharedPtr(){

    if(count!=NULL && *count == 1){

        delete _ptr;

        delete _count;

        _ptr = NULL;

        _count = NULL;

    }else{

        --(*count);

    }

}

  通過這樣的的形式,就可以保證:在多個shared_ptr物件共同維護一塊記憶體中,對記憶體只delete一次.

  最終,貼上我簡化後shared_ptr的程式碼.

<

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

/*

*檔案說明:模擬實現shared_ptr

*作者:高小調

*日期:2017-03-31

*整合開發環境:Microsoft Visual Studio 2010

*/

#pragma once

template<typename T>

class SharedPtr{

public:

    //建構函式

    SharedPtr(T *ptr=NULL)

        :_ptr(ptr)

        ,_count(NULL){

            if(ptr!=NULL){

                _count = new int(1);

                std::cout<<_ptr<<" Is Created"<<std::endl;

            }

    }

    //拷貝構造

    SharedPtr(const SharedPtr & sp)

        :_ptr(sp._ptr)

        ,_count(sp._count){

            if(sp._count!=NULL){

                ++(*_count);

            }

    }

    //賦值運算子過載

    SharedPtr& operator=(const SharedPtr &sp){

        if(_ptr!=sp._ptr){

            SharedPtr tmp(sp);

            std::swap(_ptr,tmp._ptr);

            std::swap(_count,tmp._count);

        }

        return *this;

    }

    //解構函式

    ~SharedPtr(){

        if(_count!=NULL && --(*_count)==0){

            std::cout<<_ptr<<" Is Destory"<<std::endl;

            delete _ptr;

            delete _count;

            _ptr = NULL;

            _count = NULL;

        }

    }

private:

    T* _ptr;

    int *_count;

};

 

void TestSharedPtr(){

    SharedPtr<int> sp1(new int(10));

    SharedPtr<int> sp2(new int(20));

    SharedPtr<int> sp3(new int(30));

    SharedPtr<int> sp4(sp1);

    sp2 = sp1;

    sp3 = sp1;

}