程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 用c++簡單實現智能指針

用c++簡單實現智能指針

編輯:C++入門知識

用c++簡單實現智能指針

      什麼是智能指針?答案相當簡單;智能指針是聰明的普通指針。這是什麼意思?實際上,智能指針是一些對象,表現出普通指針的功能但是比普通指針多做了一些事情。這些對象像普通指針一樣靈活,並且管理對象有自己的優點(比如構造器和自動析構)。智能指針解決了普通指針的一些問題。

      普通指針的問題。

      我們使用C++語言中的指針,最常見的問題是什麼?內存管理吧,請看下面的代碼:

[cpp]
char* pName  = new char[1024]; 
… 
SetName(pName); 
… 
… 
if(null != pName) 

       delete[] pName;  

char* pName  = new char[1024];

SetName(pName);


if(null != pName)
{
       delete[] pName;
}


      好多次我們都會忘記釋放pNme,並且管理釋放這些不會再用到的指針將會是很大的工程。可不可以指針自身進行管理?當然,智能指針就可以做到。我們實現一個智能指針,看看智能指針如何處理的更好。
      下面寫一個實際例子,先寫一個叫做Person的類。
     
[cpp]
class Person 

    int age; 
    char* pName; 
 
    public: 
        Person(): pName(0),age(0) 
        { 
        } 
        Person(char* pName, int age): pName(pName), age(age) 
        { 
        } 
        ~Person() 
        { 
        } 
 
        void Display() 
        { 
            printf("Name = %s Age = %d \n", pName, age); 
        } 
        void Shout() 
        { 
            printf("Ooooooooooooooooo"); 
        }  
}; 

class Person
{
    int age;
    char* pName;

    public:
        Person(): pName(0),age(0)
        {
        }
        Person(char* pName, int age): pName(pName), age(age)
        {
        }
        ~Person()
        {
        }

        void Display()
        {
            printf("Name = %s Age = %d \n", pName, age);
        }
        void Shout()
        {
            printf("Ooooooooooooooooo");
        }
};
下面是客戶端代碼使用Person類。

[cpp]
void main() 

    Person* pPerson  = new Person("Scott", 25); 
    pPerson->Display(); 
    delete pPerson; 

void main()
{
    Person* pPerson  = new Person("Scott", 25);
    pPerson->Display();
    delete pPerson;
}


現在我們來看這段代碼,每當我創建一個指針,都要管理釋放它。我要自動的釋放它,智能指針可以。因此我們創建一個SP類來管理Person的對象,客戶端的代碼可以這樣寫:

[cpp]
void main() 

    SP p(new Person("Scott", 25)); 
    p->Display(); 
    // Dont need to delete Person pointer..  

void main()
{
    SP p(new Person("Scott", 25));
    p->Display();
    // Dont need to delete Person pointer..
}
[cpp]
void main() 

    SP p(new Person("Scott", 25)); 
    p->Display(); 
    // Dont need to delete Person pointer..  

void main()
{
    SP p(new Person("Scott", 25));
    p->Display();
    // Dont need to delete Person pointer..
}
注意:
     1,我們創建了一個SP對象來管理Person的指針,當SP對象的作用域結束,會自動析構,它將釋放Person的指針。
     2,我們可以使用SP的對象p調用Display()函數,就像Person類的對象指針調用Display()函數,它的行為表現的像Person類的對象指針。
智能指針接口
   智能指針表現出指針的行為,所以應該支持如下運算符:
 
Dereferencing (operator *)
Indirection (operator ->)
下面實現智能指針SP:
[cpp]
class SP 

private: 
    Person*    pData; // pointer to person class  
public: 
    SP(Person* pValue) : pData(pValue) 
    { 
    } 
    ~SP() 
    { 
        // pointer no longer requried  
        delete pData; 
    } 
 
    Person& operator* () 
    { 
        return *pData; 
    } 
 
    Person* operator-> () 
    {     
        return pData; 
    } 
}; 

class SP
{
private:
    Person*    pData; // pointer to person class
public:
    SP(Person* pValue) : pData(pValue)
    {
    }
    ~SP()
    {
        // pointer no longer requried
        delete pData;
    }

    Person& operator* ()
    {
        return *pData;
    }

    Person* operator-> ()
    {   
        return pData;
    }
};
這就是我們智能指針,當它的析構函數被調用時會釋放Person類的對象指針。它也支持類似於指針的操作。
通用的智能指針
但是有個問題,我們智能控制Person類,也就是說每一種類型我們都要實現一個智能指針。我們可以使用模版使它通用。
[cpp]
template < typename T > class SP 

    private: 
    T*    pData; // Generic pointer to be stored  
    public: 
    SP(T* pValue) : pData(pValue) 
    { 
    } 
    ~SP() 
    { 
        delete pData; 
    } 
 
    T& operator* () 
    { 
        return *pData; 
    } 
 
    T* operator-> () 
    { 
        return pData; 
    } 
}; 
 
void main() 

    SP<Person> p(new Person("Scott", 25)); 
    p->Display(); 
    // Dont need to delete Person pointer..  

template < typename T > class SP
{
    private:
    T*    pData; // Generic pointer to be stored
    public:
    SP(T* pValue) : pData(pValue)
    {
    }
    ~SP()
    {
        delete pData;
    }

    T& operator* ()
    {
        return *pData;
    }

    T* operator-> ()
    {
        return pData;
    }
};

void main()
{
    SP<Person> p(new Person("Scott", 25));
    p->Display();
    // Dont need to delete Person pointer..
}
我們的智能指針這樣就真的智能了嗎?驗證下面的代碼:
[cpp]
void main() 

    SP<Person> p(new Person("Scott", 25)); 
    p->Display(); 
    { 
        SP<Person> q = p; 
        q->Display(); 
        // Destructor of Q will be called here..  
    } 
    p->Display(); 

void main()
{
    SP<Person> p(new Person("Scott", 25));
    p->Display();
    {
        SP<Person> q = p;
        q->Display();
        // Destructor of Q will be called here..
    }
    p->Display();
}
這樣就會存在一個問題:p和q關聯到了Person類的相同對象指針,當q結束它的作用域時會釋放Person類的對象指針,我們用p調用Display()函數會因為垂懸指針而失敗。我們應該在不使用它的時候再釋放,智能指針中引入計數便可解決。
計數器。
下面實現一個計數器的類RC.
[cpp]
class RC 

    private: 
    int count; // Reference count  
 
    public: 
    void AddRef() 
    { 
        // Increment the reference count  
        count++; 
    } 
 
    int Release() 
    { 
        // Decrement the reference count and  
        // return the reference count.  
        return --count; 
    } 
}; 

class RC
{
    private:
    int count; // Reference count

    public:
    void AddRef()
    {
        // Increment the reference count
        count++;
    }

    int Release()
    {
        // Decrement the reference count and
        // return the reference count.
        return --count;
    }
};
下面把計數器引入到我們的智能指針中:
[cpp]
template < typename T > class SP 

private: 
    T*    pData;       // pointer  
    RC* reference; // Reference count  
 
public: 
    SP() : pData(0), reference(0)  
    { 
        // Create a new reference   
        reference = new RC(); 
        // Increment the reference count  
        reference->AddRef(); 
    } 
 
    SP(T* pValue) : pData(pValue), reference(0) 
    { 
        // Create a new reference   
        reference = new RC(); 
        // Increment the reference count  
        reference->AddRef(); 
    } 
 
    SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference) 
    { 
        // Copy constructor  
        // Copy the data and reference pointer  
        // and increment the reference count  
        reference->AddRef(); 
    } 
 
    ~SP() 
    { 
        // Destructor  
        // Decrement the reference count  
        // if reference become zero delete the data  
        if(reference->Release() == 0) 
        { 
            delete pData; 
            delete reference; 
        } 
    } 
 
    T& operator* () 
    { 
        return *pData; 
    } 
 
    T* operator-> () 
    { 
        return pData; 
    } 
     
    SP<T>& operator = (const SP<T>& sp) 
    { 
        // Assignment operator  
        if (this != &sp) // Avoid self assignment  
        { 
            // Decrement the old reference count  
            // if reference become zero delete the old data  
            if(reference->Release() == 0) 
            { 
                delete pData; 
                delete reference; 
            } 
 
            // Copy the data and reference pointer  
            // and increment the reference count  
            pData = sp.pData; 
            reference = sp.reference; 
            reference->AddRef(); 
        } 
        return *this; 
    } 
}; 

template < typename T > class SP
{
private:
    T*    pData;       // pointer
    RC* reference; // Reference count

public:
    SP() : pData(0), reference(0)
    {
        // Create a new reference
        reference = new RC();
        // Increment the reference count
        reference->AddRef();
    }

    SP(T* pValue) : pData(pValue), reference(0)
    {
        // Create a new reference
        reference = new RC();
        // Increment the reference count
        reference->AddRef();
    }

    SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)
    {
        // Copy constructor
        // Copy the data and reference pointer
        // and increment the reference count
        reference->AddRef();
    }

    ~SP()
    {
        // Destructor
        // Decrement the reference count
        // if reference become zero delete the data
        if(reference->Release() == 0)
        {
            delete pData;
            delete reference;
        }
    }

    T& operator* ()
    {
        return *pData;
    }

    T* operator-> ()
    {
        return pData;
    }
   
    SP<T>& operator = (const SP<T>& sp)
    {
        // Assignment operator
        if (this != &sp) // Avoid self assignment
        {
            // Decrement the old reference count
            // if reference become zero delete the old data
            if(reference->Release() == 0)
            {
                delete pData;
                delete reference;
            }

            // Copy the data and reference pointer
            // and increment the reference count
            pData = sp.pData;
            reference = sp.reference;
            reference->AddRef();
        }
        return *this;
    }
};
在看看客戶端的代碼:
[cpp]
Collapse | Copy Code 
void main() 

    SP<PERSON> p(new Person("Scott", 25)); 
    p->Display(); 
    { 
        SP<PERSON> q = p; 
        q->Display(); 
        // Destructor of q will be called here..  
 
        SP<PERSON> r; 
        r = p; 
        r->Display(); 
        // Destructor of r will be called here..  
    } 
    p->Display(); 
    // Destructor of p will be called here   
    // and person pointer will be deleted  

Collapse | Copy Code
void main()
{
    SP<PERSON> p(new Person("Scott", 25));
    p->Display();
    {
        SP<PERSON> q = p;
        q->Display();
        // Destructor of q will be called here..

        SP<PERSON> r;
        r = p;
        r->Display();
        // Destructor of r will be called here..
    }
    p->Display();
    // Destructor of p will be called here
    // and person pointer will be deleted
}


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved