1.智能指针的使用和模拟实现
1.1RALL
RALL:是一种利用对象生命周期来控制程序资源的简单技术
在对象构造的时候获取资源,接着控制对资源的访问之在对象生命周期期间内始终保持有效,最后在对象析构的时候释放资源,这样做的好处有两个
1.不需要显示的释放内存
2.采用这种方式,对象所需的资源在生命周期内始终有效
举个例子(抛出异常无法释放内存)
template<class T>
class Smartptr
{
public:
Smartptr(T* ptr = nullptr)
:_ptr(ptr)
{
}
~Smartptr()
{
if (_ptr)
{
delete _ptr;
cout << "delete[] "<< endl;
}
}
private:
T* _ptr;
};
double Division(int a, int b)
{
if (b == 0)
throw "Division by zero condition!";
else
return ((double)a / (double)b);
}
void Func()
{
int* array = new int[10];
memset(array, 0, sizeof(int)* 10);
Smartptr<int> s(array);
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
system("pause");
return 0;
}
1.2只能指针的原理
上述的SmartPtr还不能将其称为智能指针,因为它不具有指针的行为,所以必须重载解引用和->访问空间所指的内容才构成智能指针。
即在SmartPtr类中重载:
T& operator*(){
return *_ptr;
}
T operator->(){
return _ptr;
}
1.3std::auto_ptr(C++98)
c++98库中提供的auto_ptr智能指针当其拷贝后就把元对象的指针悬空了,再通过原指着真访问资源时就会出现问题,所以这种指针不提倡使用。
1.4std::unique_ptr
c++11中提供了更靠谱的unique_ptr
unique_ptr的设计思路简单粗暴就是防止拷贝,下面模拟实现一下它的原理:
template <class T>
class Unique_Ptr
{
public:
Unique_Ptr(T* ptr)
:_ptr(ptr)
{}
~Unique_Ptr()
{
if(_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
//重载* ->
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
Unique_Ptr(const Unique_Ptr<T>& up);
Unique_Ptr<T>& operator=(const Unique_ptr<T>& up);
\*Unique_Ptr(const Unique_Ptr<T>& up) = delete;
Unique_Ptr<T>& operator=(const Unique_ptr<T>& up) = delete;*/
T* _ptr;
}
1.5std::share_ptr
C++11中开始提供更靠谱的并且支持拷贝的shared_ptr
share_ptr的基本原理就是::是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
- shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
- 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
- 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
- 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指 针了。
模拟实现share_ptr如下:
template <class T>
class Share_Ptr
{
public:
//构造函数在第一次申请资源后调用
Share_Ptr(T* ptr)
:_ptr(ptr)
,Use_Count(new int(1))
, _mtx(new mutex)
{}
Share_Ptr(const Share_Ptr<T>& sp)
:_ptr(sp._ptr)
, Use_Count(sp.Use_Count)
, _mtx(sp._mtx)
{
//当前指向资源的引用计数加1
addRef();
}
Share_Ptr<T>& operator=(const Share_Ptr<T>& sp)
{
//对于两个智能指针管理同一片空间的情况,不需要进行赋值
if (_ptr != sp._ptr){
if (subRef() == 0)
{
delete _ptr;
delete Use_Count;
delete _mtx;
}
_ptr = sp._ptr;
Use_Count = sp.Use_Count;
_mtx = sp._mtx;
addRef();
}
return this;
}
int addRef()
{
_mtx->lock();
++(*Use_Count);
_mtx->unlock();
return *Use_Count;
}
int subRef()
{
_mtx->lock();
--(*Use_Count);
_mtx->unlock();
return *Use_Count;
}
~Share_Ptr()
{
if (subRef() == 0)
{
if (_ptr)
{
delete _ptr;
_ptr = nullptr;
delete _mtx;
_mtx = nullptr;
delete Use_Count;
Use_Count = nullptr;
}
}
}
//重载* ->
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
int UseCount()
{
return *Use_Count;
}
private:
T* _ptr;
int* Use_Count;
//加锁,给一个全局的锁代价太大
mutex* _mtx;
};
struct Date
{
int _year;
int _month;
int _day;
~Date()
{
cout << "~Date()" << endl;
}
};
void Fun(const Share_Ptr<Date>& sp,int n)
{
for (int i = 0; i < n; i++)
Share_Ptr<Date> spcopy(sp);
}
int main()
{
Share_Ptr<Date> sp(new Date);
//Share_Ptr<Date> sp1(sp);
int n = 100000;
thread t1(Fun, sp, n);
thread t2(Fun, sp, n);
t1.join();
t2.join();
cout << sp.UseCount() << endl;
system("pause");
return 0;
}