这篇文章建大的介绍了如何编写一个智能指针。
介绍:
什么是智能指针?答案想必大家都知道,智能指针的目的就是更好的管理好内存和动态分配的资源,智能指针是一个智能的指针,顾名思义,他可以帮助我们管理内存。不必担心内存泄露的问题。实际上,智能指针是一个行为类似于指针的类,通过这个类我们来管理动态内存的分配和销毁。方便客户端的使用。相比于一般指针,智能指针主要体现在它使用的容易和便捷性。
转载请注明出处: http://blog.csdn.net/elfprincexu
使用一般指针的问题:
一般情况下我们使用指针的问题是什么?答案是内存管理,简单来看下面的一个例子:
- char* pName = new char[1024];
- SetName(pName);
- if(null != pName)
- {
- delete[] pName;
- }
在上面一段代码中,我们会遇到bug呢? 很有可能在分配内存的时候就出错了,有可能在被调用的时候指针误操作了,也有可能在其他地方操作了。答案太多太多了
我们还是从一个实际的例子开始吧,首先看下面的例子:
- 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",);
- }
- };
现在,我们开始使用这个类
- void main()
- {
- Person* pPerson = new Person("Scott", 25);
- pPerson->Display();
- delete pPerson;
- }
我们可以看到,每次我们新建一个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指向同一个实例,由于SP类没有定义拷贝函数,系统自动生成一个默认的拷贝函数,实现的是浅赋值,该内存空间被释放了两次!
所以,我们引入Reference Counting的智能指针至关重要,通过对实例被引用的次数来决定该实例是否需要被释放。
- 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;
- }
- };
现在我们有了一个RC类,这个类只做被引用的次数,唯一的数据成员就是用来跟踪被引用的次数。
结合我们刚才的SP类,我们稍作改动
- 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;
- }
- };
接下来我们看下客户端调用情况
- 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
- }
接下来,我们着重分析下上面的调用情况: