27、再论智能指针

思考:使用智能指针(SmartPointer)替换单链表(LinkList)中的原生指针是否可行?

问题出在哪里?

SmartPointer的设计方案

指针生命周期结束时主动释放堆空间。

一片堆空间最多只能由一个指针标识。LinkList多个指针指向同一对象。

杜绝指针运算和指针比较。

新的 设计方案:

Pointer是智能指针的抽象父类(模板)

纯虚析构函数virtual ~Pointer()=0 //需要被继承,此类继承自Wobject类,父类中有纯虚析构函数,所以Pointer中不用重写析构函数,只要Pointer类没有实现自己的析构函数,那他就还是个抽象类

重载operator->()

重载operator->()

#ifndef POINTER_H_
#define POINTER_H_
#include "Wobject.h"
namespace WSlib
{
template <typename T>
class Pointer:public Wobject
{
protected:
T* m_pointer;
public:
Pointer(T* p=NULL)
{
m_pointer=p;
}
T* operator ->()
{
return m_pointer;
}
    T& operator *()
{
return *m_pointer;
}
bool isNull()
{
return (m_pointer==NULL);
}
T* get() //返回成员变量的值
{
return m_pointer;
}
//继承顶层父类,此类没有实现析构函数就还是抽象类
};
}

#endif

#ifndef SMARTPOINTER_H_ 
#define SMARTPOINTER_H_
#include "Pointer.h"
namespace WSlib
{
template <typename T>
class SmartPointer:public Pointer<T>
{
//T* m_pointer;
public:
SmartPointer(T* p=NULL):Pointer<T>(p) //调用父类构造函数
{
//m_pointer=p;
}


SmartPointer(const SmartPointer<T>& obj)
{
this->m_pointer=obj.m_pointer; //加上this指针限定一下
const_cast<SmartPointer<T>&>(obj).m_pointer=NULL; //const对象必须去除const属性
}


SmartPointer<T>& operator=(const SmartPointer<T>& obj)
{
if(this != &obj)
{
T* p=this->m_pointer;
    this->m_pointer=obj.m_pointer;  //this->m_pointer=obj.m_pointer;
     //.与->的区别:两者都是二元操作符,而且右边的操作数都是成员的名称。
             // 不同点:点运算符( . )的左边操作数是一个结果为结构的表达式;
             // 箭头运算符( -> )的左边的操作数是一个指向结构体的指针
    const_cast<SmartPointer<T>&>(obj).m_pointer=NULL;  //const对象不允许赋值  必须去掉  
delete p;//如果先删除m_pointer所指的堆空间,有可能造成异常抛出,不是异常安全的,所以不能先delete
}
return *this; //可以支持连续赋值
}


/*T* operator ->()
{
//return m_pointer;
}


T* operator* ()
{
return *m_pointer;
}


bool isNull()
{
return (m_pointer==NULL);
}


T* get()
{
return *m_pointer;
}*/


~SmartPointer()
{
delete m_pointer;
}
};
}
#endif
//智能指针的使用军规:智能用来指向堆空间的单个对象或者单个变量(不能是数组或者局部对象或者局部变量)


/*******************************测试用例**************************************************
#include<iostream>
#include "SmartPointer.h"
using namespace std;
using namespace WSlib;  //必须使用自己命名空间
class Test
{
public:
Test()
{
cout<<"Test()"<<endl;
}
~Test()
{
cout<<"~Test()"<<endl;
}
};


int main()
{
SmartPointer <Test> sp=new Test(); //sp指向堆空间的地址,在析构函数中释放
    SmartPointer <Test>nsp;
nsp=sp;
//nsp++;  错的
cout<<sp.isNull()<<endl;
cout<<nsp.isNull()<<endl;
return 0;
}
*************************************顶层父类测试*********************************************
#include <iostream>
#include "SmartPointer.h"
#include "Exception.h"
using namespace std;
using namespace WSlib;
int main()
{
//SmartPointer<int>* sp=new SmartPointer<int>(); //在Wobject中new/delete中设置断点检查是否调用new/delete
//delete sp ;
InvalidOperationException* e=new InvalidOperationException();//在Wobject中new/delete中设置断点检查是否调用new/delete,不成功返回空值
delete e;
return 0;
}
**********************************************************************************/
/* WSlib的开发方式和注意事项
迭代开发:每次完成一个小的目标,持续开发,最终打造可复用类库
单一继承树:所有类都继承自Wobject,规范堆对象创建时的行为
只抛异常,不处理异常:使用THROW_EXCEPTION抛出异常,提高移植性
弱耦合性:尽量不适用标准库中的类和函数,提高可移植性*/
/*******************************27改装后********************************************************
#include <iostream>
#include "SmartPointer.h"
using namespace WSlib;
using namespace std;
class Test:public Wobject
{
public:
Test()
{
cout<<"test "<<endl;
}
~Test()
{
cout<<"~test "<<endl;
}
};


int main()
{
SmartPointer<Test> sp=new Test();
SmartPointer<Test> spn;
spn=sp;
return 0;
}
//功能没改变,改变的是构架设计
//思考如何实现SharePointer使得多个智能指针对象可以指向同一片堆内存,同时支持堆内存的自动释放

*******************************************************************************************/

28、SmartPointer不能替换原生指针使用,因为它只允许一个智能指针指向一片堆空间,多个指针不能指向同一片堆空间,限制了智能指针的应用。

目标:完成SharedPointer类的具体实现

设计要点:类模板

通过计数机制(ref)标识堆内存:

堆内存被指向时:ref++

指针被置空时:ref--

ref==0时:释放堆内存

shared_pointer_1, shared_pointer_2, shared_pointer_pointer_3---->堆中的对象(3)

对象和计数变量(保护成员指针)在一起都在堆空间,计数变量的生命周期和对象的生命周期是一样的。

智能指针的比较:由于SharedPointer支持多个对象同时指向同一片堆空间,因此,必须支持比较操作。

#ifndef SHAREDPOINTER_H_
#define SHAREDPOINTER_H_
#include <cstdlib>
#include "Pointer.h"
#include "Exception.h"
namespace WSlib
{
template <typename T>
class SharedPointer:public Pointer<T>
{
protected:
int* m_ref;
void assign(const SharedPointer<T>& obj)
{
this->m_ref=obj.m_ref;
this->m_pointer=obj.m_pointer;
if(this->m_ref)
{
(*this->m_ref)++;
}
}
public:
SharedPointer(T* p= NULL ): m_ref(NULL)
{
if(p)
{
this->m_ref=static_cast<int*>(malloc(sizeof(int)));  //malloc 返回值是 void*
if(this->m_ref)
{
*(this->m_ref)=1; //p指向一个
this->m_pointer=p;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create sharedpointer");
}
}
}
SharedPointer(const SharedPointer<T>& obj) : Pointer<T>(NULL)
{
assign(obj);
/*this->m_ref=obj.m_ref;//将当前智能指针对象的ref成员指针指向对应的计数变量,将当前智能指针对象的m_pointer成员指针指向对应的堆内存
this->m_pointer=obj.m_pointer;
if(this->m_ref)
{
*(this->m_ref)++;
}*/
}
SharedPointer<T>& operator=(const SharedPointer<T>& obj)
{
if(this !=&obj)
{
//当前智能指针对象(SharedPointer对象)可能已经指向另一片堆空间,赋值之前应当智能指针对象置空,先让他不在指向堆空间
clear();
assign(obj);
/*this->m_ref=obj.m_ref;
this->m_pointer=obj.m_pointer;
if(this->m_ref)
{
(*this->m_ref)++;
}*/
}
return *this;
}
void clear()
{
T* toDel=this->m_pointer;
int* ref=this->m_ref;
this->m_pointer=NULL;
this->m_ref=NULL;
if(ref)
{
(*ref)--;
if(*ref==0)
{
free(ref);
delete toDel;
}
}
}
~SharedPointer()
{
clear();
}
};
//通过全局函数进行重载
template<typename T>
bool operator ==(const SharedPointer<T>& l ,const SharedPointer<T>& r)
{
return (l.get()==r.get());
}
//bool operator !=(const SharedPointer<T>& l,const SharePointer<T>& r)
//{
// return !(l==r);
//}
}
#endif
/*****************************************************************************************
#include <iostream>
#include "SharedPointer.h"
using namespace WSlib;
using namespace std;
class Test:public Wobject
{
public:
int value;
Test():value(0)
{
cout<<"test "<<endl;
}
~Test()
{
cout<<"~test "<<endl;
}
};


int main()
{
SharedPointer<Test> sp0=new Test();
SharedPointer<Test> sp1=sp0;
SharedPointer<Test> sp2=NULL;
sp2=sp1;
  sp2->value=100;


cout<<sp0->value<<endl;
cout<<sp1->value<<endl;
cout<<sp2->value<<endl;
sp2.clear();
cout<<(sp0==sp2)<<endl;
const SharedPointer<Test> sp3=new Test();
//sp3->value=100;
return 0;
}
//功能没改变,改变的是构架设计
//思考如何实现SharePointer使得多个智能指针对象可以指向同一片堆内存,同时支持堆内存的自动释放
//智能指针使用军规:只能用来指向堆空间(不能是栈或全局数据区)中的单个变量(对象),
//不同类型的智能指针对象不能混合使用,不要使用delete释放智能指针指向的堆空间。
//小结:SharePointer最大程度的模拟了原生指针的行为,计数机制确保多个智能指针合法的指向同一片堆空间,
//智能指针只能用于指向堆空间中的内存,不同类型的智能指针不要混合使用,堆对象的生命周期由智能指针进行管理。
作业:用SharedPointer替换LinkList中的原生指针,思考:内部是否需要使用智能指针,为什么?
*********************************************************************************************/

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80405896