c++【深度剖析shared_ptr】
2016-11-21 08:31
344 查看
shared_ptr解决了scoped_ptr管理单个对象的缺陷,且解决了防拷贝的问题。shared_ptr可以管理多个对象,并且实现了资源共享。
但是仍然存在一些问题,比如,我们熟悉的双向链表:
struct Node
{
Node(const int& value)
:_pNext(NULL)
,_pPre(NULL)
,_value(value)
{}
Node* _pNext;
Node* _pPre;
int _value;
};
这个双向链表对于shared_ptr会有什么影响呢?
1、shared_ptr的循环引用问题
先看如下代码:
运行结果:
这就是shared_ptr实现的双向链表的模型,在此处引起了循环引用的问题。
如图:
当分别创建完sp1,sp2后,它们各自的use_count为1;当再次执行
这两句后,sp1,sp2的use_count分别加为2;
此时,析构对象时use_count会减为1;但不等于0,所以它不会释放,这就导致了循环引用问题。
那么如何解决循环引用问题呢?我们又引出了另外一个智能指针:weak_ptr(它是一个弱指针,用来和shared_ptr搭配使用的)
2、解决循环引用问题
运行结果:
其实,在shared_ptr和weak_ptr的引用计数的基类中,有两个计数:一个是_Uses,一个是_Weaks;
shared_ptr:当指向一片区域时,引用计数会使用_Uses来++;
weak_ptr:当指向一片区域时,引用计数会使用_Weaks来++;
最终看的还是use_count,使用weak_ptr时use_count仍为1;所以析构时可以成功释放。
3、定置删除器
原理:对于像文件类型的指针,用shared_ptr释放时,无法释放,因为在底层没有对文件指针的直接释放,所以得自己手动将其close掉。
void FunTest()
{
FILE* file = fopen("1.txt","r");
shared_ptr<FILE> sp(file);
}
这时,就要使用我们的定置删除器:(此处用了STL的六大组件之一-----仿函数)
//成功的关闭文件:
//类似的,对于我们malloc出来的空间,需要free掉时,同样也可以用仿函数的形式:
4、冒泡排序的升级版(仿函数的形式)
有时候,当面试官让你写一个冒泡排序的时候,你不知道面试官到底让你写的是升序还是降序,此时就比较尴尬了哈,你可以问一下面试官也是可以的,当然还有一种更巧妙的方法就是:你可以用仿函数的方式,把两种方式都实现了,需要哪种用哪种即可。
#include<iostream>
using namespace std;
template<typename T>
class Greater
{
public:
bool operator()(const T&left,const T& right)
{
return left>right;
}
};
template<typename T>
class Less
{
public:
bool operator()(const T&left,const T& right)
{
return left<right;
}
};
template<typename T,typename Fun>
void BubbleSort(T arr[],size_t size)
{
for(size_t i = 0; i < size-1; i++)
{
for(size_t j = 0; j < size-i-1;++j)
{
if(Fun()(arr[j],arr[j+1]))
{
T tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
void FunTest()
{
int arr[] = {2,5,4,1,6,9,8,7};
BubbleSort<int,Greater<int>>(arr,sizeof(arr)/sizeof(arr[0]));
BubbleSort<int,Less<int>>(arr,sizeof(arr)/sizeof(arr[0]));
}
int main()
{
FunTest();
return 0;
}
如果可以写成这种程度,肯定会使面试官眼前一亮。哈哈
但是仍然存在一些问题,比如,我们熟悉的双向链表:
struct Node
{
Node(const int& value)
:_pNext(NULL)
,_pPre(NULL)
,_value(value)
{}
Node* _pNext;
Node* _pPre;
int _value;
};
这个双向链表对于shared_ptr会有什么影响呢?
1、shared_ptr的循环引用问题
先看如下代码:
#include<iostream> using namespace std; #include<boost/shared_ptr.hpp> template<typename T> class Node { public: Node(const T& value) :_pNext(NULL) ,_pPre(NULL) _value(value) {} shared_ptr<Node<T>> _pNext; shared_ptr<Node<T>> _pPre; T _value; }; void FunTest() { shared_ptr<Node<int>> sp1(new Node<int>(1)); shared_ptr<Node<int>> sp2(new Node<int>(2)); cout<<sp1.use_count()<<endl; cout<<sp2.use_count()<<endl; sp1->_pNext = sp2; sp2->_pPre = sp1; cout<<sp1.use_count()<<endl; cout<<sp2.use_count()<<endl; }
运行结果:
这就是shared_ptr实现的双向链表的模型,在此处引起了循环引用的问题。
如图:
当分别创建完sp1,sp2后,它们各自的use_count为1;当再次执行
sp1->_pNext = sp2; sp2->_pPre = sp1;
这两句后,sp1,sp2的use_count分别加为2;
此时,析构对象时use_count会减为1;但不等于0,所以它不会释放,这就导致了循环引用问题。
那么如何解决循环引用问题呢?我们又引出了另外一个智能指针:weak_ptr(它是一个弱指针,用来和shared_ptr搭配使用的)
2、解决循环引用问题
#include<iostream> using namespace std; #include<boost/shared_ptr.hpp> template<typename T> class Node { public: Node(const T& value) :_value(value) {} T _value; weak_ptr<Node<T>> _pNext; weak_ptr<Node<T>> _pPre; }; void FunTest() { shared_ptr<Node<int>> sp1(new Node<int>(1)); shared_ptr<Node<int>> sp2(new Node<int>(2)); cout<<sp1.use_count()<<endl; cout<<sp2.use_count()<<endl; sp1->_pNext = sp2; sp2->_pPre = sp1; cout<<sp1.use_count()<<endl; cout<<sp2.use_count()<<endl; }
运行结果:
其实,在shared_ptr和weak_ptr的引用计数的基类中,有两个计数:一个是_Uses,一个是_Weaks;
shared_ptr:当指向一片区域时,引用计数会使用_Uses来++;
weak_ptr:当指向一片区域时,引用计数会使用_Weaks来++;
最终看的还是use_count,使用weak_ptr时use_count仍为1;所以析构时可以成功释放。
3、定置删除器
原理:对于像文件类型的指针,用shared_ptr释放时,无法释放,因为在底层没有对文件指针的直接释放,所以得自己手动将其close掉。
void FunTest()
{
FILE* file = fopen("1.txt","r");
shared_ptr<FILE> sp(file);
}
这时,就要使用我们的定置删除器:(此处用了STL的六大组件之一-----仿函数)
//成功的关闭文件:
#include<iostream> using namespace std; #include<boost/shared_ptr.hpp> struct FClose { void operator()(FILE *file) { fclose(file); cout<<"fclose()"<<endl; } }; void FunTest() { FILE* file = fopen("1.txt","w"); shared_ptr<FILE> sp(file,FClose()); }
//类似的,对于我们malloc出来的空间,需要free掉时,同样也可以用仿函数的形式:
struct Free { void operator()(void *ptr) { free(ptr); cout<<"free()"<<endl; } }; void FunTest() { int *p = (int *)malloc(sizeof(int)); shared_ptr<int> sp(p,Free()); }
4、冒泡排序的升级版(仿函数的形式)
有时候,当面试官让你写一个冒泡排序的时候,你不知道面试官到底让你写的是升序还是降序,此时就比较尴尬了哈,你可以问一下面试官也是可以的,当然还有一种更巧妙的方法就是:你可以用仿函数的方式,把两种方式都实现了,需要哪种用哪种即可。
#include<iostream>
using namespace std;
template<typename T>
class Greater
{
public:
bool operator()(const T&left,const T& right)
{
return left>right;
}
};
template<typename T>
class Less
{
public:
bool operator()(const T&left,const T& right)
{
return left<right;
}
};
template<typename T,typename Fun>
void BubbleSort(T arr[],size_t size)
{
for(size_t i = 0; i < size-1; i++)
{
for(size_t j = 0; j < size-i-1;++j)
{
if(Fun()(arr[j],arr[j+1]))
{
T tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
void FunTest()
{
int arr[] = {2,5,4,1,6,9,8,7};
BubbleSort<int,Greater<int>>(arr,sizeof(arr)/sizeof(arr[0]));
BubbleSort<int,Less<int>>(arr,sizeof(arr)/sizeof(arr[0]));
}
int main()
{
FunTest();
return 0;
}
如果可以写成这种程度,肯定会使面试官眼前一亮。哈哈
相关文章推荐
- C++ shared_ptr源码剖析
- C++智能指针shared_ptr剖析
- 从汇编层面深度剖析C++虚函数
- 从汇编层面深度剖析C++虚函数
- C++深度剖析(一) this指针与虚表
- 深度剖析一个典型的C/C++程序的编译、链接以及执行的过程
- 从汇编层面深度剖析C++虚函数
- C++学习(四) 深度剖析堆与栈
- C++开发:为什么多线程读写shared_ptr要加锁的详细介绍
- c++ shared_ptr智能指针使用注意事项
- 【C/C++和指针】深度剖析----强制类型转换(一)
- 从汇编层面深度剖析C++基本对象布局 .
- 说说C++智能指针(1): 关于shared_ptr
- 基于LINUX平台G++编译器从汇编层面深度剖析C++虚函数
- 【转】C++ std::tr1::shared_ptr使用
- C++小品:吃火锅与shared_ptr,指针,拷贝构造函数和delete
- 从汇编层面深度剖析C++基本对象布局
- C++ std::tr1::shared_ptr使用
- 从汇编层面深度剖析C++基本对象布局
- C++ boost shared_ptr as a hash_map key