这篇文章建大的介绍了如何编写一个智能指针。
介绍:
什么是智能指针?答案想必大家都知道,智能指针的目的就是更好的管理好内存和动态分配的资源,智能指针是一个智能的指针,顾名思义,他可以帮助我们管理内存。不必担心内存泄露的问题。实际上,智能指针是一个行为类似于指针的类,通过这个类我们来管理动态内存的分配和销毁。方便客户端的使用。相比于一般指针,智能指针主要体现在它使用的容易和便捷性。
转载请注明出处: 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
}
接下来,我们着重分析下上面的调用情况: