首先提出: scoped_ptr是boost库中对这个只能指着的叫法,unique_ptr是C++11标准库中对这个智能指针的叫法
上一篇我们讲解了智能指针中的auto_ptr,但是auto_ptr中还是有很大的缺陷,于是在boost库中,各位民间大佬提出了另外几种智能指针,分别是 scoped_ptr,shared_ptr,还有配合shared_ptr使用的weak_ptr
这一片我们讲解一下scoped_ptr的原理及其用法
我们看到,在之前的auto_ptr中最大的缺陷就在于拷贝构造和赋值运算符的重载这两个函数中,所以scoped_ptr就想了一个比较绝对的方法,就是禁止我们使用拷贝构造和赋值运算符的重载。
下面给出三种防拷贝的方法,我们观察一下
思想: 将拷贝构造函数和赋值运算符的重载都在类中声明,并给出一个空的定义
template
class ScopedPtr
{
public:
ScopedPtr(T* ptr = nullptr):_ptr(ptr)
{}
~ScopedPtr()
{
if(_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
ScopedPtr(const ScopedPtr& ap){}
ScopedPtr& operator=(const ScopedPtr& ap){}
private:
T* _ptr;
};
这种方法好吗? 答案是,肯定不好
在类内给出了空定义 -> 这一点很好,完美的防止了在类外这两个函数被别人重新定义
访问限定符为公有 -> 这点就非常的不好了,我们做到的不应该仅仅是防止拷贝,还应该做的是让使用者直到这两个函数是根本不能调用的
思想: 为了解决上面的问题,我们将这两个成员函数设计为私有成员函数
template
class ScopedPtr
{
private:
ScopedPtr(const ScopedPtr& ap){}
ScopedPtr& operator=(const ScopedPtr& ap){}
public:
ScopedPtr(T* ptr = nullptr):_ptr(ptr)
{}
~ScopedPtr()
{
if(_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
private:
T* _ptr;
};
这个方法好吗? 答案是,比上面的方法优秀了一丢丢~~~
但是但是但是,我们不要忘记了,C++中有一个破坏封装性的利器,就是友元函数,看下面
template
class ScopedPtr
{
friend void Test1();
private:
ScopedPtr(const ScopedPtr& ap){}
ScopedPtr& operator=(const ScopedPtr& ap){}
public:
ScopedPtr(T* ptr = nullptr):_ptr(ptr)
{}
~ScopedPtr()
{
if(_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
private:
T* _ptr;
};
void Test1()
{
ScopedPtr p1(new int);
ScopedPtr p2(p1);
p1 = p2;
}
在上面的例子中,Test1()是Scoped_ptr的友元函数,所以可以在Test1()函数中访问类的私有成员,这个时候我们在类外面访问这两个本想防拷贝的函数时,用户也根本就不知道这个函数 不 ! 能 ! 被 ! 拷 ! 贝 !
思想: 将拷贝构造函数和赋值运算符的重载声明为私有的,并且,只声明不定义~
template
class ScopedPtr
{
private:
ScopedPtr(const ScopedPtr& ap);
ScopedPtr& operator=(const ScopedPtr& ap);
public:
ScopedPtr(T* ptr = nullptr):_ptr(ptr)
{}
~ScopedPtr()
{
if(_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
};
将拷贝构造和赋值运算符的重载声明为私有成员 -> 在类外并不可以访问
只声明不定义 -> 是告诉了用户这个函数时不能使用的,因为我们根本就没有实现啊
上面的scoped_ptr存在问题: 对数组无法管理,所以有了 ScopedArray
scoped_array实现起来也是比较简单的,和scoped_ptr基本是一致的
template
class ScopedArray
{
public:
ScopedArray(T* ptr = nullptr)
:_ptr(ptr)
{
cout<<"ScopedArray()"<&);
ScopedArray& operator=(const ScopedArray&);
private:
T* _ptr;
};
只是比之前新增了对数组的操作,重载了[]运算符
scoped_ptr实现的最终原理是,将拷贝构造和赋值运算符的重载都声明为私有成员,并且不进行定义,这样在类外我们是无法使用的。
为了解决数组的问题,我们引进了scoped_array,进行有关于数组的智能指针,并且重载了数组相关的操作。
scoped_ptr是boost库中的叫法,在C++11中,标准委员会正式将这个智能指针引入标准库,但是,划重点了,
在C++11中并不叫scoped_ptr,而是unique_ptr!!!
C++11实现的unique_ptr以后,并没有去实现unique_array,是因为标准库中有vector,其实是很好用的