您的位置:首页 > 运维架构

智能指针(模拟实现AutoPtr、ScopedPtr、SharedPtr)

2016-03-24 17:28 369 查看
模拟实现AutoPtr、ScopedPtr、SharedPtr

智能指针实际上就是能够智能化的管理动态开辟空间的内存释放问题,C++中引入智能指针,很大一方面是当我们在动态开辟空间时,由于一些疏忽,或者说是对于一些代码,执行的顺序不是我们预期能够想到的,导致一些内存泄露的问题,使得程序健壮性不够,可维护性降低。

智能指针的基本特点:
1)智能指针管理的是一块内存的释放。
2)智能指针是一个类,有类似指针的功能。

下面主要是AutoPtr的理解:
当我们了解上面的知识后,模拟实现智能指针AutoPtr,可能会写出下列的代码:
//智能指针AutoPtr

template <class T>
class AutoPtr
{
public:
AutoPtr(T * ptr)
:_ptr(ptr)
{ }

~AutoPtr()
{
cout << "delete" << _ptr << endl;
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}

private:
T * _ptr;
};
上面的代码是存在一些问题的,class AutoPtr只是实现了构造函数和析构函数,对于拷贝构造函数和赋值运算符重载是系统默认的,系统默认情况下是值拷贝,存在一块空间被释放两次及以上的情况,导致程序运行错误。对于以前string类的实现采用的是“深拷贝”,但是在这种情况下,不能采用深拷贝来解决,需要使得两个指针必须指向同一块空间。AutoPtr的原理就是将第一个指向这块空间的指针直接置为空,然后进行析构。这样就不会存在上述问题。





AutoPtr(AutoPtr<T> & ap)       //拷贝构造
:_ptr(ap._ptr)
{
ap._ptr = NULL;
cout << "kaobei" << endl;
}

AutoPtr<T> & operator=(AutoPtr<T> & ap)
{
if (this != &ap)
{
delete _ptr;
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
//下面是实现*、->等功能
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* GetPtr()
{
return _ptr;
}
这里要说明的是,AutoPtr这个指针尽量不要使用,因为可能在写代码时不注意就会出错。

下面主要是ScopedPtr的理解:

因为智能指针容易出现拷贝时释放两次的情况,所以ScopedPtr主要是进行防止拷贝,防止拷贝的两条必须要满足的条件是:
1)设置保护限定符,
2)对拷贝构造函数和赋值运算符重载进行之声明不定义。
如若只有2),没有设置保护限定符,若在类外进行定义后,则会出现问题,所以说这两个条件是必不可少的。这样就能够避免上面所出现的问题,但是这样就造成了它在功能上的缺陷。

//ScopedPtr    实现简单的智能指针
//进行防拷贝
template <class T>
class ScopedPtr
{
public:
ScopedPtr(T * ptr)
:_ptr(ptr)
{ }

~ScopedPtr()
{
cout << "delete" << endl;
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}

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

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

T* GetPtr()
{
return _ptr;
}

protected:     //防止拷贝
ScopedPtr(ScopedPtr<T> & ap);
ScopedPtr<T> & operator=(ScopedPtr<T> & ap);

private:
T * _ptr;
};
ScopedPtr指针是比较容易实现的,如果面试时出现需要实现一个智能指针的题目,可以考虑实现ScopedPtr,毕竟可以在短时间内实现,也同样较实现AutoPtr好一些。

下面主要是SharedPtr的理解:

SharedPtr指针主要的原理是利用引用计数的浅拷贝来实现,通过多开辟4个字节的方式,存储引用计数,当有指针指向这块空间时,引用计数+1。如若析构时,先将这块空间的引用计数降为1,然后在进行析构,避免了析构多次的问题。

template <class T>
//智能指针sharedptr
class SharedPtr
{
public:
SharedPtr(T * ptr)
:_ptr(ptr)
, _pcount(new long(1))
{ }

~SharedPtr()
{
cout << "delete" << endl;
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
}

SharedPtr(SharedPtr<T> & ap)
:_ptr(ap._ptr)
, _pcount(ap._pcount)
{
++(*_pcount);
}

SharedPtr<T> & operator=(SharedPtr<T> & ap)
{
if (this != &ap)
{
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
_ptr = ap._ptr;
_pcount = ap._pcount;
++(*_pcount);
}
return *this;
}

private:
T * _ptr;
long *_pcount;    //实现引用计数
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息