用c++简单实现智能指针

 

用c++简单实现智能指针

      什么是智能指针?答案相当简单;智能指针是聪明的普通指针。这是什么意思?实际上,智能指针是一些对象,表现出普通指针的功能但是比普通指针多做了一些事情。这些对象像普通指针一样灵活,并且管理对象有自己的优点(比如构造器和自动析构)。智能指针解决了普通指针的一些问题。

      普通指针的问题。

      我们使用C++语言中的指针,最常见的问题是什么?内存管理吧,请看下面的代码:

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


      好多次我们都会忘记释放pNme,并且管理释放这些不会再用到的指针将会是很大的工程。可不可以指针自身进行管理?当然,智能指针就可以做到。我们实现一个智能指针,看看智能指针如何处理的更好。
      下面写一个实际例子,先写一个叫做Person的类。
     
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类。

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


现在我们来看这段代码,每当我创建一个指针,都要管理释放它。我要自动的释放它,智能指针可以。因此我们创建一个SP类来管理Person的对象,客户端的代码可以这样写:

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:
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类,也就是说每一种类型我们都要实现一个智能指针。我们可以使用模版使它通用。
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..
}

我们的智能指针这样就真的智能了吗?验证下面的代码:
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.
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;
    }
};

下面把计数器引入到我们的智能指针中:
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;
    }
};

在看看客户端的代码:
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
}

 


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值