您的位置:首页 > 编程语言 > C语言/C++

C++智能指针(二):模拟实现三种智能指针

2017-08-10 21:47 531 查看
上一篇博客我们简单介绍了智能指针:简单介绍智能指针

有关shared_ptr的循环引用问题可以参考博客:weak_ptr–解决shared_ptr循环引用问题

auto_ptr

模拟实现

template<class T>
class Autoptr
{
public:
Autoptr(T* ptr = NULL)
:_ptr(ptr)
{}

Autoptr(Autoptr<T>& ap)
{
_ptr = ap._ptr;
ap._ptr = NULL;
}

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;
}

~Autoptr()
{
delete _ptr;
_ptr = NULL;
}

void Reset(T* ptr = 0)
{
if (_ptr != ptr)
{
delete _ptr;
}
_ptr = ptr;
}
protected:
T* _ptr;
};

void APTest()
{
Autoptr<int> ap1(new int(10));
cout <<"*ap1 = "<< *ap1 << endl;

Autoptr<int> ap2(ap1);
cout <<"*ap2 = "<< *ap2 << endl;

Autoptr<int> ap3(new int(20));
ap3 = ap2;
cout <<"*ap3 = "<< *ap3 << endl;

//cout << *ap1 << endl;//报错
}


测试结果:



代码分析

代码中的Reset()函数是干嘛的?

void Reset(T* ptr = 0)
{
if (_ptr != ptr)
{
delete _ptr;
}
_ptr = ptr;
}


答:为了重置一个auto_ptr对象,必须使用reset()函数。可以向reset()传递一个指针,如果不希望设置该auto_ptr对象的话,可以传递一个0值。如果auto_ptr当前指向一个对象并且该auto_ptr对象拥有该对象的所有权,则该对象再底层指针重置之前,首先被删除。例如:

void APTest()
{
int *pi = new int(20);
auto_ptr<int>_auto_ptr(pi);
cout << "_auto_ptr = " << *pi << endl;

int *pi2 = new int(30);
_auto_ptr.reset(pi2);
cout << "pi->" << *pi << endl;
cout << "pi2->" << *pi2 << endl;
}


输出结果:



我们可以在输出结果的第二行看到,pi已经变成了随机值。reset()函数将auto_ptr对象原来指向的那块动态分配的空间释放了。

上面的代码还有一句:

//cout << *ap1 << endl;//报错


为什么报错??

这是因为ap1已经把它指向的空间交给了ap2去管理,所以ap1已经不具备访问原来自己所指向的空间的权限。所以对它进行解引用是非法的。

所以可以看清auto_ptr的本质是管理权的转移,即ap1将自己所指向的空间交给ap2来管理,析构也是由ap2来完成。

scoped_ptr

由于auto_ptr的严重缺陷,所以后来引入了scoped_ptr。防拷贝,意思就是不能进行拷贝,简单地说是一种简单粗暴的方式。

模拟实现

template<class T>
class  Scopedptr
{
public:
Scopedptr(T* ptr = NULL)
:_ptr(ptr)
{}

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

T operator*()
{
return *_ptr;
}

~Scopedptr()
{
delete _ptr;
_ptr = NULL;
}

protected:
Scopedptr(Scopedptr<T>& sp);
Scopedptr<T>& operator=(const Scopedptr<T>& p);
private:
T* _ptr;
};

void SPTest()
{
Scopedptr<int> sp(new int(10));
cout << "sp = " << *sp << endl;
}


scoped_ptr中对拷贝构造函数和赋值运算符的重载函数只是进行了声明,并没有去定义这两个函数,而且声明为protected或者是private,这是防止别人在类外对这两个函数进行定义。防止拷贝,所以说scope_dptr是一种简单粗暴的方式。

shared_ptr

编写程序往往要用到拷贝,这样scopedptr就不能起到相应的作用,所以便有了shared_ptr。

shared_ptr->采用了引用计数,优点是功能强大,但是也有缺点,缺点是过于复杂,而且会引起循环引用。

template<class T>
class Sharedptr
{
public:
Sharedptr(T* ptr = NULL)

c68b
:_ptr(ptr)
, pcount(0)
{
if (_ptr != NULL)
pcount = new int(1);
}

Sharedptr(const Sharedptr<T>& sp)
{
_ptr = sp._ptr;
pcount = sp.pcount;
++(*pcount);
}

Sharedptr<T>& operator=(const Sharedptr<T>& sp)
{
if (this != &sp)
{
if (_ptr && --(*pcount) == 0)
{
delete pcount;
delete _ptr;
}
pcount = sp.pcount;
_ptr = sp._ptr;
++(*pcount);
}

return *this;
}

~Sharedptr()
{
if (_ptr && --(*pcount) == 0)
{
delete _ptr;
delete pcount;
}
}

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

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

T Getpcount()
{
return *(pcount);
}

void Realease()
{
if (--(*pcount) == 0)
{
delete _pcount;
delete _ptr;
}
}

void Reset(T* ptr, int* pcount)
{
if (_ptr != ptr)
{
delete _ptr;
delete _pcount;
}

_ptr = ptr;
_pcount = pcount;
}
private:
T* _ptr;
T* pcount;
};

void Test()
{
Sharedptr<int> s1(new int(10));
cout << "s1 = " << *s1 << endl;
cout << "pcount = " << s1.Getpcount() << endl;

Sharedptr<int> s2(s1);
cout << "s2 = " << *s2 << endl;
cout << "pcount = " << s2.Getpcount() << endl;

Sharedptr<int> s3;
s3 = s1;
cout << "s3 = " << *s3 << endl;
cout << "pcount = " << s3.Getpcount() << endl;
}


测试结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  智能指针 C++