shared_ptr是一种智能指针数据结构,除了具有智能指针的基本功能——自动管理资源释放外,还有一个特征就是"share",我理解所谓的“share”就是多个shared_ptr共同分享同一处资源,避免了资源的拷贝。比如,当执行拷贝构造函数操作时:
class X{...};
shared_ptr<X> px1(new X());
shared_ptr<X> px2(px1);
或是赋值操作时:
class X{...};
shared_ptr<X> px1(new X(...));
shared_ptr<X> px2(new X(...));
px2 = px1;
shared_ptr不进行资源的拷贝,而是将内部的指针指向相应的资源即可。以上例子中,px2并不会从px1中拷贝资源,而是将内部指针指向px1中的资源。
那么px2或px1被销毁时会发生什么?会将其指向的内部资源同时销毁吗?不会。现在的资源是大家公用的,不能被随意销毁。shared_ptr是采用引用计数(reference counting)来控制资源的指向和销毁。内部资源会伴有一个计数值count,count表示有多少个shared_ptr指向该资源,每当有一个新的shared_ptr指向该资源时,count值加1,当有一个指向该资源的shared_ptr销毁时,count值减1,当count变为0时,证明所有指向该资源的shared_ptr已经销毁,此时内部资源也被销毁。
自己写了一个简单的shared_ptr模板类,如下:
template<class T>
class my_shared_ptr{
public:
my_shared_ptr(T* pt){
_pBlock = new ControlBlock(pt);
}
my_shared_ptr(const my_shared_ptr& rhs){
_pBlock = rhs._pBlock;
_pBlock->ref_count++;
}
~my_shared_ptr(){
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
}
my_shared_ptr& operator=(const my_shared_ptr& rhs){
if(this == &rhs)
return *this;
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
_pBlock = rhs._pBlock;
_pBlock->ref_count++;
}
T* get(){return _pBlock->_ptr;}
T* operator->(){return _pBlock->_ptr;}
void reset(T* pt){
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
_pBlock = new ControlBlock(pt);
}
private:
struct ControlBlock{
int ref_count;
T* _ptr;
ControlBlock(T* pt){
_ptr = pt;
ref_count = 1;
}
~ControlBlock(){
delete _ptr;
}
};
ControlBlock* _pBlock;
};
my_shared_ptr内部有一个ControlBlock管理内部资源,同时有一个计数值ref_count标记指向该内部资源的my_shared_ptr个数。在拷贝构造函数和赋值操作符中,都有:
_pBlock = rhs._pBlock;
_pBlock->ref_count++;
语句,这两句表示当发生my_shared_ptr的拷贝时,不拷贝内部资源,而是将内部指针指向同样的内部资源,并增加计数值。
在析构函数中可以看到如下语句:
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
表示内部资源不是随意销毁的,析构函数会减小计数值,当计数值变为0时,内部资源才会销毁。
在赋值操作符函数中,首先进行自检,其次释放本身指向的内部资源,之后指向新的内部资源,并更新计数值。
测试程序如下:
#include "my_shared_ptr.h"
#include <iostream>
using namespace std;
class X{
public:
X(int i):_val(i){
cout << "X(" << _val << ") constructed." << endl;
}
~X(){
cout << "X(" << _val << ") destructed." << endl;
}
void print(){
cout << "X(" << _val << ")::print()." << endl;
}
private:
int _val;
};
int main(){
my_shared_ptr<X> shared_px1(new X(10));
my_shared_ptr<X> shared_px2(new X(20));
shared_px1->print();
shared_px2->print();
shared_px2 = shared_px1;
shared_px1->print();
shared_px2->print();
}
执行结果如下:
X(10) constructed.
X(20) constructed.
X(10)::print().
X(20)::print().
X(20) destructed.
X(10)::print().
X(10)::print().
X(10) destructed.
可以看到,在执行赋值操作符函数后,shared_px2所指向的内部资源被销毁, 因为X(20)被析构;之后shard_px2和shared_px1指向了同一个内部资源,因为都打印了X(10)::print(). 程序结束时,所有内部资源都被自动销毁。