您的位置:首页 > 其它

智能指针

2016-04-14 11:20 375 查看
对于一个初学者,常常会被野指针(垂悬指针)的问题所困扰。这就用到了我们今天讨论的智能指针来解决问题。
野指针,也就是指向不可用内存区域的指针。通常对这种指针进行操作的话,将会使程序发生不可预知的错误。
[b]“野指针”不是NULL指针,是指向“垃圾”内存的指针。[/b]人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用,野指针一般不会为NULL。野指针的成因主要有两种:
(一)指针变量定义时没有被初始化
char* p;
strcpy(p, “world”);//出错,没有初始化
(二)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针
char* p=(char*)malloc(4*sizeof(char));
free(p);
if(p!=NULL)//不能防止p不为空
{strcpy(p, “world”);}//非法的拷贝,出错
所以,在定义一个指针的时候最好就初始化,在释放指针内存时把指针置空。如果你觉得你都想不起来的话,那么掌握智能指针是必须掌握的。
智能指针是用一个类来实现的,有类似指针的功能。
智能指针大概分为三种:
(一)AutoPtr。这种智能指针是最早使用的一类智能指针,它的实现方式就是转移管理权。它有两种历史版本
template<class T>
class AutoPtr
{
private:
T* _ptr;
bool _owner;
}

template<class T>
class AutoPtr
{
private:
T* _ptr;
}




第二个版本显然比第一个版本好,也是库后来采用的版本。如果用第一个版本的对象s1拷贝构造s2。
AutoPtr<T> s2(s1);出了作用域后析构函数将释放s2,但是s1仍然指向那块空间,使用s1将发生错误。
(二)ScopedPtr。这种方法更为直接,竟然拷贝构造和赋值重载都会发生错误,那么我就不让你使用这两个函数,直接放入protected或者private中,这样在类外就无法调用这两个函数,也不用定义这两个函数,只用声明即可。
template<class T>
class ScopedPtr
{
public:

protected:
ScopedPtr(const ScopedPtr<T>& sp);
ScopedPtr<T> operator=(const ScopedPtr<T>& sp);

protected:
T* _ptr;
};
防卫智能指针在指针之间不进行拷贝和赋值时是非常有用的,效率高。
(三)SharedPtr。带引用计数的智能指针,这种智能指针是用途最广泛的智能指针。
template<class T>
class SharedPtr
{
public:
SharedPtr(T* ptr)
:_ptr(ptr)
,_pCount(new long(1))
{}

SharedPtr(const SharedPtr<T>& sp)
:_ptr(sp._ptr)
,_pCount(sp._pCount)
{
++(*_pCount);
}
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if (this != &sp)
{
_pCount = sp._pCount;
_ptr = sp._ptr;
++(*_pCount);
}

return *this;
}
~SharedPtr()
{
if (--(*_pCount) == 0)//当引用计数为1时释放空间
{
//delete _ptr;
_del(_ptr);
delete _pCount;
}
}
protected:
T* _ptr;
long* _pCount;
};





每个智能指针对象里都有一个引用计数,并不是所有的智能指针对象共用一个引用计数,也不是每个对象都用自己的一个引用计数,对于指向同一块内存空间的智能指针共用一个引用计数。 这就解决了两个指针指向一块空间,当析构一个指针时,另一个指针出问题的情况。每当引用计数为1时才释放指向的那块空间,不然就引用计数减1. (四)WeakPtr。WeakPtr是辅助SharedPtr使用的智能指针,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: