指针用于访问程序外部的资源,例如堆内存。因此,如果在堆内存中创建了任何东西,则可以用指针访问堆内存。
我们先通过此例来了解:普通指针面对的主要问题是什么:
#include
using namespace std;
class Rectangle
{
private:
int length;
int breadth;
}
void fun()
{
// By taking a pointer p and dynamically creating object of class rectangle
Rectangle* p = new Rectangle();
}
int main()
{
// Infinite loop
while(1)
{
fun();
}
}
上述代码:
#include
using namespace std;
class SmartPtr
{
int* ptr; // Actual pointer
public:
// for use of explicit keyword
explicit SmartPtr(int* p = NULL) {
ptr = p;
}
// Destructor function
~SmartPtr(){
delete(ptr);
}
// overloading dereferencing operator
int& operator*()
{
return *ptr;
}
}
int main(){
// 构造SmartPtr对象 ptr
SmartPtr ptr(new int());
// 重载了 operatpr*() 操作符
*ptr = 20;
cout << *ptr;
return 0;
}
在编写一个:适用于所有类型的智能指针。
是的,我们可以用模板编写通用的智能指针类,以下是C++ 代码演示了相同的过程。
这种智能指针的应用是最广泛的。
tmplate<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)
{
_del(_ptr);
delete _pCount;
}
}
protected:
T* _ptr;
long* _pCount;
}
#include
using namespace std;
template<class T>
class Smart_ptr
{
public:
Smart_ptr(T* ptr = nullptr)
{
mptr = ptr;
}
~Smart_ptr(){
delete mptr;
}
private:
T* mptr;
}
int main(){
// 以前的写法
// int* p = new int;
// delete p;
// 现在替换成下面智能指针的方式
Smart_ptr<int> sp(new int);
return 0;
}
重载操作符(* 和 ->)让其具备裸指针的一些功能
#include
using namespace std;
template<class T>
class Smart_ptr
{
public:
Smart_ptr(T* ptr = nullptr)
{
mptr = ptr;
}
~Smart_ptr(){
delete mptr;
}
T& operator*(){
return *(this->mptr);
}
T* operator->(){
return this->mptr;
}
private:
T* mptr;
}
int main(){
Smart_ptr<int> sp(new int);
*sp = 20;
cout << *sp << endl;
return 0;
}
在版本 v0.2中,上面代码是不带引用计数的,那么它会暴露如下问题
int main()
{
Smart_ptr<int> sp(new int);
Smart_ptr<int> ps(sp);
return 0;
}
很显然在V0.2b版本中,如果出现上面情况,就会发生崩溃,这是为什么了?
因为在出作用域后,ps 先先析构,把资源释放了,等到 sp 再次析构的时候,就有资源释放了。
解决方案
~Smart_ptr(){
delete mptr;
mptr = nullptr;
}
带引用计数的智能指针:shared_ptr和 weak_ptr,可以使用多个智能指针管理同一个资源,实现方式就是:给每一个对象资源匹配一个引用计数。
#include
using namespace std;
template<class TT>
class Refcnt
{
public:
Refcnt(TT* ptr = nullptr)
{
mptr = ptr;
if(mptr) {mcount = 1;}
}
void addRef()
{
mcount++;
}
int delRef()
{
return --mcount;
}
private:
TT* mptr;
int mcount;
}
template<class T>
class smart_ptr
{
smart_ptr(T* ptr = nullptr)
{
mptr = ptr;
mRefCnt = new Refcnt<T>(mptr);
}
~smart_ptr()
{
if(0 ==mRefcnt->delRef())
{
delete ptr;
mptr = nullptr;
}
}
T& operator*(){
return *(this->mptr);
}
T* operator->(){
return this->mptr;
}
smart_ptr<T>& operator=(smart_ptr<T> ptr)
{
if(this == &ptr)
{
return *this;
}
if(0==mRefcnt->delRef())
{
delete mptr;
}
mptr = ptr.mptr;
mRefcnt = ptr->mRefcnt;
mRefcnt->addRef();
return *this;
}
private:
T* mptr; // 指向资源
Refcnt<T>* mRefcnt;// 指向引用计数
}
int main()
{
smart_ptr<int> sp(new int);
smart_ptr<int> ps(sp);
return 0;
}
在v0.4版本中,使用 shared_ptr 这个称为强指针,强指针有个很严重的问题就是:循环引用或者交叉引用。