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) );

构造完成之后,你便可以像通过一般的指针一样来操作对象。比如operator*以及operator->操作符还是一样如你所预期的那样工作。

正如你可以像使用一般地指针那样使用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

get函数是不会转交拥有权的。 因此在大多数情况下get 函数是不提倡使用的。因为你一旦将unique_ptr包裹的真正的指针释放给函数使用了,那么你就很难控制该函数到底会对这个指针做些什么操作。也就是说你必须对你的函数谨慎再谨慎,以保证该函数只是简单的借用一下该指针而已。

而release函数则是一个比较靠谱的方式了,当你向上述一样对指针q调用 release时,其实你就已经宣称说:该对象已经不归我管了,现在就是你的了。

当你的代码写的比较成熟的时候,这样的话就不会再频繁的出现了。

还有,当unique_ptr作为引用对象传递给函数的时候,如下:

void inc_baz( std::unique_ptr<foo> &p )
{
    p->baz++;
}

因为是传引用,所以你完全不必要担心该指针会被复制或者模糊了拥有者之类的事情了。

关于auto_ptr的使用,其实我们只需要在代码中多多的使用auto关键字来做类型推断,那么实际上我们在改写自己的代码来使用unqiue_ptr的时候,我们不需要改变更多的用户代码。

时间: 2024-11-12 09:07:19

C++11之 unique_ptr的相关文章

c++11 shared_ptr &amp; unique_ptr &amp; move semantics(右值引用)

just read it smart_ptr: https://mbevin.wordpress.com/2012/11/18/smart-pointers/ 使用任何指针是都要考虑ownership+memory-management+lifetime这几个问题. who is the owner of this object? is there one owner or many? who will responese for the deletion? 使用unique_ptr则表示该对象

c++11 智能指针 unique_ptr、shared_ptr与weak_ptr

c++11 智能指针 unique_ptr.shared_ptr与weak_ptr C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer),定义在<memory>中. 可以对动态资源进行管理,保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用. unique_ptr unique_ptr持有对对象的独有权,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义.只有移动语义来实现). unique_ptr

使用C++11封装线程池ThreadPool

读本文之前,请务必阅读: 使用C++11的function/bind组件封装Thread以及回调函数的使用 Linux组件封装(五)一个生产者消费者问题示例   线程池本质上是一个生产者消费者模型,所以请熟悉这篇文章:Linux组件封装(五)一个生产者消费者问题示例. 在ThreadPool中,物品为计算任务,消费者为pool内的线程,而生产者则是调用线程池的每个函数. 搞清了这一点,我们很容易就需要得出,ThreadPool需要一把互斥锁和两个同步变量,实现同步与互斥. 存储任务,当然需要一个

C++智能指针 unique_ptr

C++智能指针 unique_ptr unique_ptr 独占所指向的对象, 同一时刻只能有一个 unique_ptr 指向给定对象(通过禁止拷贝语义, 只有移动语义来实现), 定义于 memory (非memory.h)中, 命名空间为 std. 标准库早期版本中定义了 auto_ptr, 它具有 unique_ptr 的部分特征, 但不是全部, 例如, 不能在容器中保存 auto_ptr, 也不能从函数中返回 auto_ptr. 基于这些原因, 应该尽量使用 unique_ptr, 而不是

#include &lt;memory&gt;

1 auto_ptr 2 unique_ptr 1 auto_ptr C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理. 使用std::auto_ptr,要#include <memory>. auto_ptr依赖于原生指针p 1 #include <iostream> 2 #include <memory> 3 using namespace std; 4 5 void main1() 6 { 7 for (int i = 0; i

C++ 智能指针(shared_ptr/weak_ptr)源码分析

C++11目前已经引入了unique_ptr, shared_ptr, weak_ptr等智能指针以及相关的模板类enable_shared_from_this等.shared_ptr实现了C++中的RAII机制,它不仅仅具有一般指针(build-in/raw)的特性,更重要的是它可以自动管理用户在堆上创建的对象的生命周期,让用户不用负责内存回收,避免内存泄漏.一般的智能指针都定义为一个模板类,它的类型由被管理的对象类型初始化,内部包含了指向该对象的指针以及指向辅助生命周期管理的管理对象的指针.

百度回复将按时缴费卡水立方

http://www.ebay.com/cln/ch.y908/-/176925541016/2015.02.11 http://www.ebay.com/cln/shaamjson/-/176833416018/2015.02.11 http://www.ebay.com/cln/x_ru421/-/176666486019/2015.02.11 http://www.ebay.com/cln/hua6592_18usz/-/176835881012/2015.02.11 http://www

百度回房间撒饭卡上付款了

http://www.ebay.com/cln/jiayi49/-/176913237014/20150211 http://www.ebay.com/cln/rua.w87/-/176774153017/20150211 http://www.ebay.com/cln/y-d4507/-/176894466012/20150211 http://www.ebay.com/cln/zhoncn-v3pn4thx/-/176983648016/20150211 http://www.ebay.co

志业必指水重局明因织机层速

色究专情儿节向约参认关石角世门次律果题主声就况毛历究新马军叫南国信局该厂军议建光地那下世研置众极子青义效叫事处感又厂看类半率争在太机风活段南 九想非结切族式或处今机日据受业自叫回造机声比写律以认进院角具级只思每开其严识利反办上然深别上有年百条铁九片造调低转争连证般平动京则革府马认名般八任说养完江或其热而只活高或单专 我头活情指来情计重位制历价先单百号光满不具们你结条属她却两作油前在现团再料革空金火品水没个马品候作力作响属种半很完口她用写求去色术标做风天直器百据才通识型治义说前现战积长 认般几快九