新智能指针的加入:
C++11之前,智能指针只有 auto_ptr 一种,但是后来发现它并不能很好的保证指针的安全可靠性,随之又出现了
shared_ptr unique_ptr weak_ptr scope_ptr 这几种智能指针。
假如存在这样的代码
int main()
{
SmartPtr<int> sp1(new int);
SmartPtr<int> sp2(sp1);
*sp1 = 20;
return 0;
}
这里,SmartPtr即为之前博客实现的auto_ptr,显而易见,*sp1=20;这行会出现崩溃。
解决方案:
之前的auto_ptr,管理权唯一,释放权也唯一,现在要使智能指针管理权不唯一,释放权唯一。
带有标志位(flag)的智能指针
如图:
代码:
#include<iostream>
using namespace std;
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* ptr) :mptr(ptr)
{
flag = true;
}
SmartPtr(const SmartPtr<T>& rhs):mptr(rhs.mptr)
{
flag = rhs.flag;
rhs.flag = false;
}
SmartPtr<T>& operator=(const SmartPtr<T>& rhs)
{
if (this != &rhs)
{
~SmartPtr();
mptr = rhs.mptr;
flag = rhs.flag;
rhs.flag = false;
}
return *this;
}
~SmartPtr()
{
if (flag)
{
delete mptr;
}
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T* mptr;
mutable bool flag;//去除常性
};
int main()
{
SmartPtr<int> sp1(new int);
SmartPtr<int> sp2(sp1);
SmartPtr<int> sp3(sp1);
*sp1 = 20;
return 0;
}
这里程序不会崩溃,有释放权的只有sp2。
又一个问题
因为释放权的转移,有可能导致堆内存被提前释放
void func(SmartPtr<int> sp)//实参传形参 调用拷贝构造
{
}
int main()
{
SmartPtr<int> sp1(new int);
SmartPtr<int> sp2(sp1);
SmartPtr<int> sp3(sp1);
func(sp2);//;执行结束后,形参对象销毁 相当于堆内存已经归还给系统
*sp1 = 20;//使用不可使用的内存块 野指针 该内存块可能被再分配
return 0;
}
调用这个函数,实参传形参 调用拷贝构造,func(sp2);//;执行结束后,形参对象销毁 相当于堆内存已经归还给系统。
*sp1 = 20;//使用不可使用的内存块 野指针 该内存块可能被再分配,会出现不可预期的数据错误。
解决: ScopePtr 不允许多个智能指针对象指向同一块堆内存
#include<iostream>
using namespace std;
template<typename T>
class ScopePtr//不允许多个智能指针对象指向同一块堆内存
{
public:
ScopePtr(T* ptr=NULL):mptr(ptr)
{
//mptr = ptr;
}
~ScopePtr()
{
delete mptr;
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
ScopePtr(const ScopePtr<T>& rhs);//不需要调用,因为不允许多个智能指针对象指向同一块堆内存
ScopePtr<T>& operator=(const ScopePtr<T>& rhs);//不允许多个智能指针对象指向同一块堆内存
private:
T* mptr;
};
int main()
{
int* p = new int;
ScopePtr<int> sp1(p);
ScopePtr<int> sp2(p);
ScopePtr<int> sp3(p);//后构造的先析构
return 0;
}
int* p = new int;
ScopePtr<int> sp1(p);
ScopePtr<int> sp2(p);
ScopePtr<int> sp3(p);//后构造的先析构
这个程序会崩溃,后构造的先析构,然后先构造的再析构时,delete野指针,程序崩溃。