|
为什么有智能指针:
因为C++中没有回收内存的机制,当我们new一块内存时,如果忘记了delete,会产生异常导致程序奔溃,为了解决这个问题,引入了智能指针来管理内存。
智能指针的原理:
智能指针的原理就是RAII。RAII:资源的分配即初始化,定义一个类来封装资源的分配和释放,在构造函数来进行资源的分配和初始化,在析构函数来释放资源,资源的正常使用。
智能指针其实是一个栈对象,并不是一个指针类型。
C++标准库中的智能指针:
1. auto_ptr:主要是管理权转移,当一个对象构造另一个对象时,转移关系权限。
模拟实现:
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* ptr)
:_ptr(ptr)
{}
AutoPtr(AutoPtr<T>& ap)
{
//权限转移
_ptr=ap._ptr ;
ap._ptr =NULL;
}
~AutoPtr()
{
if(_ptr!=NULL)
{
delete _ptr;
}
}
AutoPtr<T>& operator=(AutoPtr<T>& ap)
{
if(this!=&ap)
{
delete _ptr;
_ptr=ap._ptr ;
ap._ptr =NULL;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;//返回地址
}
void display()
{
cout<<*_ptr<<endl;
}
private:
T* _ptr;
};
Boost库中的智能指针:
2.scoped_ptr:和auto_ptr一样,但不允许拷贝构造和赋值。
模拟实现scoped_ptr
template<typename T>
class ScopedPtr //不允许拷贝构造和赋值
{
public:
ScopedPtr(T* ptr)
:_ptr(ptr)
{}
~ScopedPtr()
{
if(_ptr!=NULL)
{
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;//返回地址
}
void display()
{
cout<<*_ptr<<endl;
}
protected: //防止拷贝构造和赋值
ScopedPtr(const ScopedPtr<T>& sp);
ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
private:
T* _ptr;
};
3.shared_ptr:共享内存,采用引用计数的方法。当计数器为0时,释放内存。
模拟实现shared_ptr:
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr)
:_ptr(ptr)
,_pcount(new int(1))
{}
SharedPtr(const SharedPtr<T>& sp)
{
_ptr=sp._ptr;
_pcount=sp._pcount ;
++(*_pcount);
}
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if(this!=&sp)
{
if(--(*_pcount)==0)
{
delete _ptr;
delete _pcount;
}
_ptr=sp._ptr ;
_pcount=sp._pcount ;
++(*_pcount);
}
return *this;
}
T& operator[](size_t index)
{
if((*_pcount)>1)
{
--(*_pcount);
T* Newptr=new T;
T* Newpcount=new int(1);
_ptr=Newptr;
_pcount=Newpcount;
}
return _ptr[index];
}
T& operator*()
{
if((*_pcount)>1)
{
--(*_pcount);
T* Newptr=new T;
T* Newpcount=new int(1);
_ptr=Newptr;
_pcount=Newpcount;
}
return *_ptr;
}
~SharedPtr()
{
if(--*_pcount==0)
{
delete _ptr;
delete _pcount;
}
}
void display()
{
cout<<*_ptr<<" "<<*_pcount<<endl;
}
private:
T* _ptr;
T* _pcount;
};
存在的问题:
(1).线程安全:???
(2).循环引用:为了解决这个问题引入了weak_ptr。
struct Node
{
int data;
boost::shared_ptr<Node> _next;
boost::shared_ptr<Node> _prev;
//boost::weak_ptr<Node> _next; //为了解决这种情况,引用了弱指针
//boost::weak_ptr<Node> _prev;
~Node()
{
cout<<"~Node()"<<endl;
}
};
void test()
{
boost::shared_ptr<Node> sp1(new Node());
boost::shared_ptr<Node> sp2(new Node());
cout<<sp1.use_count() <<endl;
cout<<sp2.use_count() <<endl;
sp1->_next =sp2;
sp2->_prev =sp1;
cout<<sp1.use_count() <<endl;
cout<<sp2.use_count() <<endl;
} 此时的运行结果为:1 1 2 2
为什么没有打印析构这句话:因为出现了循环指向对方,各自的引用计数都是2,对方都在等对方先delete,然后自己才能delete,用shared_ptr导致两个都不会delete。
为了解决这个问题,现在我们引入了weak_ptr,weak_ptr是为了shared_ptr准备的,它不能单独使用,他是来辅助shared_ptr的,weak_ptr的构造函数只能接受shared_ptr类型的对象。
(3).定制删除器:shared_ptr只能解决new出来的,对于文件类型,malloc出来的,它就不行,需要我们进行定制解决方法。
class Fclose
{
public:
void operator()(void *ptr)
{
cout<<"fclose"<<endl;
fclose((FILE*)ptr);
}
};
class Free
{
public:
void operator()(void *ptr)
{
cout<<"free"<<endl;
free(ptr);
}
};
void test4()
{
boost::shared_ptr<FILE> sp1(fopen("test.txt","w"),Fclose());
boost::shared_ptr<int> sp2((int*)malloc(sizeof(int)),Free());
}
4.还有scoped_array,shared_array,intrusive_ptr等智能指针。
|