标签:des style blog http color io os ar 使用
看到文章里的同学留言说到unique_ptr,这两天看了一下cplusplus提供的reference才知道这个东西是c++11的新特性,对c++11的新特性不是很了解,花时间了解了下unique_ptr,之前有写过auto_ptr的分析,这里就和auto_ptr对比下来看。
1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 int *p = new int(12);
4 unique_ptr<int> up(p);
5 unique_ptr<int> up2(p);
6
7 return 0;
8 }
up析构时,已经将p指针delete,而up2析构会重复delete,出现未定义操作。auto_ptr析构函数只是单纯的delete掉raw指针,而unique_ptr则可以定制自己的deleter,来指定unique_ptr析构时需要做哪些工作。默认情况下unique_ptr使用的deleter如下:
1 void operator()(_Ty *_Ptr) const _NOEXCEPT
2 { // delete a pointer
3 static_assert(0 < sizeof (_Ty),
4 "can‘t delete an incomplete type");
5 delete _Ptr;
6 }
可以看出这是一个函数对象,功能很简单,delete raw指针。开发人员可以定制自己的deleter,一个很简单的例子:
1 struct my_deleter
2 {
3 void operator()(int *p)
4 {
5 cout<<"delete point, value = "<<*p<<endl;
6 delete p;
7 }
8 };
9 int _tmain(int argc, _TCHAR* argv[])
10 {
11 unique_ptr<int, my_deleter> up(new int(12), my_deleter());
12
13 return 0;
14 }
1 struct Item
2 {
3 Item(){cout<<"Construct "<<endl;}
4 ~Item() {cout<<"Destruct"<<endl;}
5 };
6 int _tmain(int argc, _TCHAR* argv[])
7 {
8 Item *par = new Item[5];
9 unique_ptr<Item[]> uparr(par);
10
11 return 0;
12 }
在vs2012中运行上面的代码结果如下,根据输出中五个"Destruct"可以看出uparr对象在析构时调用了delete[]:
1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 int *p = new int(12);
4 unique_ptr<int> up(p);
5 unique_ptr<int> up_copy(up);
6 unique_ptr<int> up_assign;
7 up_assign = up;
8
9 return 0;
10 }
因为此特性,猜想unique_ptr对象无法很好地与STL容器一起使用(PS:最初我以为将拷贝构造和赋值操作符私有化的类,声明一个容器持有这种类型,这样的代码编译就会报错,编码后才知道编译不会报错,调用push_back等需要拷贝或赋值的操作时,才会报错),下面代码中line5将会报错:
1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 unique_ptr<int> up(new int(12));
4 vector<unique_ptr<int> > vup;
5 vup.push_back(up);
6
7 return 0;
8 }
之后了解到c++11中引入的move语义使得unique_ptr可以存放到容器中,参考这篇文章http://www.th7.cn/Program/cp/201408/267890.shtml。使用move就表示放弃对该对象的所有权,但并不对raw指针进行释放,举个例子:
1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 vector<unique_ptr<int, my_deleter> > vup;
4 {
5 cout<<"scope begin######################"<<endl;
6 unique_ptr<int, my_deleter> up(new int(12), my_deleter());
7 vup.push_back(move(up));
8 if(up.get() == NULL)
9 cout<<"up points NULL"<<endl;
10 cout<<"scope end######################"<<endl;
11 }
12 cout<<"outer######################"<<endl;
13
14 return 0;
15 }
根据下面的输出可以验证,在局部对象up经过move函数调用后,失去了对raw指针的所有权(line9),并未释放raw指针,之后如果误用了up对象,会导致undefine行为:
这里需要注意的是,此处move函数调用了unique_ptr的move语意拷贝构造函数(不知道c++11是否这么称呼……),注意形参类型为unique_ptr&&
1 unique_ptr(unique_ptr&& _Right) _NOEXCEPT
2 : _Mybase(_Right.release(),
3 _STD forward<_Dx>(_Right.get_deleter()))
4 { // construct by moving _Right
5 }
这里确实没有调用deleter,进行raw指针的释放。forward函数同样是c++11里的语法,表示”接受一个参数,然后返回该参数本来所对应的类型的引用”。
目前对unique_ptr的了解就到这里,不算太深,可以看出unique_str的功能比auto_ptr更为强大,它支持托管堆上分配的数组,支持定制deleter,并且可以通过move语意使unique_ptr对象与容器兼容,但仍然有一些不足,比如重复释放,使用move语意之后源对象失去了对raw指针的管理权,再次使用会出现undefine行为。要避免这些情况,除了使用时要注意之外,最好的办法还是使用带有引用计数功能的智能指针。
标签:des style blog http color io os ar 使用
原文地址:http://www.cnblogs.com/Tour/p/4047169.html