标签:c++11 unique_ptr
原文地址为:http://www.drdobbs.com/cpp/c11-uniqueptr/240002708
在C++11中加入了很多的新特性,unique_ptr一枝独秀,对于动态分配的内存对象,它简单有效。虽然它不是万能的,但是它做的已经够好了:利用简单的语法便可以管理动态分配的对象。
基本语法:
unique_ptr<T> 是一个模板类,你可以很简单地构造一个unique_ptr的对象,如下:
std::unique_ptr<foo> p( new foo(42) );
正如你可以像使用一般地指针那样使用unique_ptr类,最最重要的还是你可以unique_ptr会在超出作用域时自动的销毁该对象。你不必担心在作用域的某个出口忘记delete导致内存泄露,甚至在出现异常之后它也可以自动的销毁对象。
unique_ptr与容器:
到目前为止,一切都是幸运的,根据标准C++的语法你同样可以实现上面的那些种种功能,实际上,auto_ptr这个不幸者(C++11已经将其废弃掉了)便是可以实现上述功能的,作为一个RAII的包裹器。
不行的是,auto_ptr并不能适当的工作,即使对于一些基本的操作,auto_ptr的表现也不尽人意。例如,如果你需要创建一个存放auto_ptr的容器,那么这将是一个大问题.
补充:关于对象与容器的关系,下面我自己写了一段简单的代码以作理解:
class A { public: A() {cout << "A ctor called..." << endl;} A(const A&) {cout <<"A copy ctor called..." << endl;} }; int main(void) { vector<A> vec; for(int i=0;i<5;++i) { cout << " i = " << i << endl; vec.push_back(A()); //构造该对象并且复制该对象。见下面代码的运行结果 } return 0; }
可以看到,上述代码的执行结果中调用了拷贝构造函数。
[continue] 步入正题:
C++11加入了右值引用(rvalue reference) 和 move语意(move semantic) 来解决这些问题。幸运的是,经过修复,unique_ptr可以存储在容器中,即使容器被resize并且或者是被move都有正确的语意。并且当容器被销毁时,这些指针管理的资源也可以被正常的销毁。
唯一性与move语意:
unique这个词到底意味着什么呢?就如其字面意思一样,当你创建一个unique_ptr时,你就宣称这个指针就是独一份的,没有歧义的,就只有你可以拥有它,别人不可能也不会不经意的复制它。
比如,对于一个一般的指针,有如下代码:
foo *p = new foo("useful object");
make_use(p) ; // make_use函数的参数是一个对象指针
这里,我分配了一个对象并且有一个指针p指向它,当我在调用make_use函数的时,指针p会发生什么呢?make_use会为该指针做一份拷贝吗?在调用完毕之后会释放掉内存吗?或者说它就只是简单的借用一会儿该指针就原封不动的还回来,让调用者去释放空间呢?
上面的问题我们一个也无法回答, 是因为C++本身并没有对怎么使用指针这件事情作任何的约定,你只有通过查看自己的代码,查看自己的把内存以及文档来解决。
所幸的是,有了unique_ptr,这些问题都不是问题了,如果你传了一个指针给另外一个例程(权当函数理解了)。你不会对该指针做一份copy(因为它是unique的),即使你那样做,编译器也是不答应的。
指针的拥有者:
首先来一个简单的例子:创建一个unique_ptr,将其存放在一个容器中。作为一个unique_ptr的新手,你可能写出下面的代码:
std::unique_ptr<foo> q( new foo(42) ); v.push_back( q );
面对这些纠结,unique_ptr 禁止这样的代码。编译这样的代码将会导致编译错误。
Anyway,这里的问题就是我们只允许有该指针的一份拷贝。如果你想要将该对象交给另一个对象,就必须调用move函数,也就是说你必须放弃掉该对象的拥有权。
如:
v.push_back( std::move(q) );
执行完上述语句之后,q已经变成空的了,因为q已经放弃了该对象的拥有权,将拥有权交给了容器。
move语意可以用在任何你需要创建一个“右值引用”的地方。例如下面的代码:
return q;
返回一个unique_ptr则不需要任何特殊的代码就可以完成。
还有,创建一个临时的对象给一个需要unique_ptr的函数也是不需要特殊处理的。如:
process( std::unique_ptr<foo>( new foo(41) ) );
Legacy Code: 老程序,其实也就是兼容性啦。
当你在使用unqiue_ptr的时候。你发现你现在需要的是一个底层的指针,那么有两种方式:
do_something( q.get() ); //retain ownership do_something_else( q.release() ); //give up ownership
而release函数则是一个比较靠谱的方式了,当你向上述一样对指针q调用 release时,其实你就已经宣称说:该对象已经不归我管了,现在就是你的了。
当你的代码写的比较成熟的时候,这样的话就不会再频繁的出现了。
还有,当unique_ptr作为引用对象传递给函数的时候,如下:
void inc_baz( std::unique_ptr<foo> &p ) { p->baz++; }
关于auto_ptr的使用,其实我们只需要在代码中多多的使用auto关键字来做类型推断,那么实际上我们在改写自己的代码来使用unqiue_ptr的时候,我们不需要改变更多的用户代码。
标签:c++11 unique_ptr
原文地址:http://blog.csdn.net/xuqingict/article/details/38796341