shared_ptr虽然方便,但是它有着一个致命的缺陷就是循环引用问题,因为shared_ptr本身并没有能力解决这个问题,所以我们又引入了弱指针weak_ptr来辅助shared_ptr解决这个问题。
那么循环引用又是什么场景?
举个栗子:
假设现在我们要创建一个双向×××链表,但是这个链表的指针域全部都用shared_ptr维护:
struct Node
{
int _data;
shared_ptr<Node> _next;
shared_ptr<Node> _prev;
}
假设现在先创建两个结点,并用shared_ptr维护这两个结点:
shared_ptr<Node> sp1(new Node);
shared_ptr<Node> sp2(new Node);
现在将这两个指针互相连接:
sp1->_next=sp2;
sp2->prev=sp1;
为了解决循化引用问题,我们又引入了weak_ptr弱指针,用来辅助shared_ptr。注意weak_ptr不能单独使用,必须辅助shared_ptr才能使用。weak_ptr是一种不控制所指向对象生存周期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一但最后一个指向对象的shared_ptr被销毁,对象就会被销毁,即使有weak_ptr指向对象,对象还是会被释放。
例:
所以为了解决上面栗子中的循环引用问题,我们可以将指针域的智能指针声明为弱指针。
struct Node
{
int _data;
weak_ptr<Node> _next;
weak_ptr<Node> _prev;
}
二、定置删除器
一般情况下,我们都用智能指针是用来管理动态内存的,其实智能指针是用来管理资源的,资源很多,动态内存只是资源的一种,比如说我们可以用智能指针来管理文件,那么我们就不能用智能指针默认的删除器了,因为要管理文件的话最后是fclose,而不是delete,所以我们就必须自己定制一个删除器。
例:以管理文件为例,实现定置删除器。
要实现定置删除器,就要用到仿函数:仿函数就是将"()"重载。
//定置删除器的仿函数
struct Fclose
{
void operator()(void *ptr)
{
fclose((FILE *)ptr);
cout << "fclose()" << endl;
}
};
void test()
{
boost::shared_ptr<FILE> sp(fopen("test.txt","w"),Fclose()); //调用构造函数构造一个匿名对象传递过去,文件正常关闭
}
再举一个栗子:
用智能指针管理malloc开辟的动态内存,那么我们在释放的时候就要用free释放:
//定置删除器的仿函数
struct Free
{
void operator()(void *ptr)
{
free(ptr);
}
};
void test()
{
boost::shared_ptr<int> sp((int *)malloc(sizeof(int)),Free()); //能够正确的释放空间
}
三、简单的实现一个有定置删除器的shared_ptr
struct Fclose
{
void operator()(void *ptr)
{
fclose((FILE *)ptr);
cout << "fclose()" << endl;
}
};
struct Free
{
void operator()(void *ptr)
{
free(ptr);
cout << "free()" <<endl;
}
};
//默认删除器是delete
struct DefaultDel
{
void operator()(void* ptr)
{
delete ptr;
cout << "delete ptr" << endl;
}
};
template<typename T, typename D = DefaultDel>
class SharedPtr //采用引用计数,实现一个可以有多个指针指向同一块内存的类模板,SharedPtr是类模板,不是智能指针类型
{
public:
SharedPtr(T* ptr, D del = DefaultDel());
SharedPtr(const SharedPtr<T,D>& sp);
SharedPtr<T,D>& operator=(SharedPtr<T,D> sp);
T& operator*();
T* operator->();
~SharedPtr();
int Count()
{
return *_pCount;
}
private:
void Release()
{
if (--(*_pCount) == 0)
{
_del(_ptr);
delete _pCount;
_ptr = NULL;
_pCount = NULL;
}
}
private:
T* _ptr;
int* _pCount;
D _del;
};
template<typename T, typename D = DefaultDel>
SharedPtr<T,D>::SharedPtr(T* ptr,D del)
:_ptr(ptr)
, _pCount(new int(1))
,_del(del){}
template<typename T, typename D = DefaultDel>
SharedPtr<T,D>::SharedPtr(const SharedPtr<T,D>& sp)
{
_ptr = sp._ptr;
_pCount= sp._pCount;
++(*_pCount);
}
template<typename T, typename D = DefaultDel>
SharedPtr<T,D>& SharedPtr<T,D>::operator=(SharedPtr<T,D> sp)
{
std::swap(sp._ptr,_ptr);
std::swap(sp._pCount,_pCount);
return *this;
}
template<typename T, typename D = DefaultDel>
T& SharedPtr<T,D>::operator*()
{
return *_ptr;
}
template<typename T, typename D = DefaultDel>
T* SharedPtr<T,D>::operator->()
{
return _ptr;
}
template<typename T, typename D = DefaultDel>
SharedPtr<T,D>::~SharedPtr()
{
Release();
}
//测试用例
void test()
{
SharedPtr<int> sp(new int(1));
SharedPtr<FILE,Fclose> sp1(fopen("test.txt","w"),Fclose());
SharedPtr<string,Free> sp3((string *)malloc(sizeof(string)),Free());
}
int main()
{
test();
system("pause");
return 0;
}
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。