C++ 11智能指针之shared_ptr



shared_ptr是一个引用计数智能指针,用于共享对象的所有权。它可以从一个裸指针、另一个shared_ptr、一个auto_ptr、或者一个weak_ptr构造。还可以传递第二个参数给shared_ptr的构造函数,它被称为删除器(deleter)。删除器用于处理共享资源的释放,这对于管理那些不是用new分配也不是用delete释放的资源时非常有用。shared_ptr被创建后,就可以像普通指针一样使用了,除了一点,它不能被显式地删除。shared_ptr的比较重要的接口如下:

template <class T>

explicit shared_ptr(T* p);

这个构造函数获得给定指针p的所有权。参数p必须是指向T的有效指针。构造后引用计数设为1。唯一从这个构造函数抛出的异常是std::bad_alloc(仅在一种很罕见的情况下发生,即不能获得引用计数器所需的空间)。

template <class T,class D>

shared_ptr(T* p,D d);

这个构造函数带有两个参数。第一个是shared_ptr将要获得所有权的那个资源,第二个是shared_ptr被销毁时负责释放资源的一个对象,被保存的资源将以d(p)的形式传给那个对象。如果引用计数器不能分配成功,shared_ptr抛出一个类型为std::bad_alloc的异常。

shared_ptr(const shared_ptr& r);

r中保存的资源被新构造的shared_ptr所共享,引用计数加一。这个构造函数不会抛出异常。

template <class T>

explicit shared_ptr(const weak_ptr<T>& r);

从一个weak_ptr构造shared_ptr。这使得weak_ptr的使用具有线程安全性,因为指向weak_ptr参数的共享资源的引用计数将会自增(weak_ptr不影响共享资源的引用计数)。如果weak_ptr为空(r.use_count()==0), shared_ptr抛出一个类型为bad_weak_ptr的异常。

template <typename T>

shared_ptr(auto_ptr<T>& r);

这个构造函数从一个auto_ptr获取r中保存的指针的所有权,方法是保存指针的一份拷贝并对auto_ptr调用release。构造后的引用计数为1,而r则变为空的。如果引用计数器不能分配成功,则抛出std::bad_alloc。

~shared_ptr();

shared_ptr析构函数,对引用计数减一。如果计数为零,则保存的指针被删除。删除指针的方法是调用operator delete,或者,如果给定了一个执行删除操作的删除器对象,就把保存的指针作为唯一参数调用这个对象。析构函数不会抛出异常。

shared_ptr& operator=(const shared_ptr& r);

赋值操作共享r中的资源,并停止对原有资源的共享。赋值操作不会抛出异常。

void reset();

reset函数用于停止对保存指针的所有权的共享。共享资源的引用计数减一。

T& operator*() const;

这个操作符返回对已存指针所指向的对象的一个引用。如果指针为空,调用operator*会导致未定义行为。这个操作符不会抛出异常。

T* operator->() const;

这个操作符返回保存的指针。这个操作符与operator*一起使得智能指针看起来象普通指针。这个操作符不会抛出异常。

T* get() const;

get函数是当保存的指针有可能为空时(这时 operator* 和 operator-> 都会导致未定义行为)获取它的最好办法。注意,你也可以使用隐式布尔类型转换来测试shared_ptr是否包含有效指针。这个函数不会抛出异常。

bool unique() const;

这个函数在shared_ptr是它所保存指针的唯一拥有者时返回true;否则返回false。 unique不会抛出异常。

long use_count() const;

use_count 函数返回指针的引用计数。它在调试的时候特别有用,因为它可以在程序执行的关键点获得引用计数的快照。小心地使用它,因为在某些可能的shared_ptr实现中,计算引用计数可能是昂贵的,甚至是不行的。这个函数不会抛出异常。

operator unspecified-bool-type() const;

这是个到unspecified-bool-type类型的隐式转换函数,它可以在Boolean上下文中测试一个智能指针。如果shared_ptr保存着一个有效的指针,返回值为True;否则为false。注意,转换函数返回的类型是不确定的。把返回类型当成bool用会导致一些荒谬的操作,所以典型的实现采用了safe bool idiom,它很好地确保了只有可适用的Boolean测试可以使用。这个函数不会抛出异常。

void swap(shared_ptr<T>& b);

这可以很方便地交换两个shared_ptr。swap函数交换保存的指针(以及它们的引用计数)。这个函数不会抛出异常。

template <typename T,typename U>  shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);

要对保存在shared_ptr里的指针执行static_cast,我们可以取出指针然后强制转换它,但我们不能把它存到另一个shared_ptr里;新的shared_ptr会认为它是第一个管理这些资源的。解决的方法是用static_pointer_cast,使用这个函数可以确保被指对象的引用计数保持正确。static_pointer_cast不会抛出异常。

使用shared_ptr的示例代码如下:

1 {

2 shared_ptr<int> pInt1;

3 assert(pInt1.use_count() == 0);         // 还没有引用指针

4 {

5       shared_ptr<int> pInt2(new int(5));

6       assert(pInt2.use_count() == 1);        // new int(5)这个指针被引用1次

7

8     pInt1 = pInt2;

9       assert(pInt2.use_count() == 2);       // new int(5)这个指针被引用2次

10     assert(pInt1.use_count() == 2);

11 }                                                   //pInt2离开作用域, 所以new int(5)被引用次数-1

12

13 assert(pInt1.use_count() == 1);

14 }         // pInt1离开作用域,引用次数-1,现在new int(5)被引用0次,所以销毁它

如果资源的创建销毁不是以new和delete的方式进行的,该怎么办呢?通过前面的接口可以看到,shared_ptr的构造函数中可以指定删除器。示例代码如下:

1 class FileCloser

2 {

3 public:

4     void operator()(FILE *pf)

5     {

6          if (pf != NULL)

7          {

8                fclose(pf);

9                pf = NULL;

10          }

11     }

12 };

13

14 shared_ptr<FILE> fp(fopen(pszConfigFile, "r"), FileCloser());

在使用shared_ptr时,需要避免同一个对象指针被两次当成shard_ptr构造函数里的参数的情况。考虑如下代码:

1 {

2      int *pInt = new int(5);

3      shared_ptr<int> temp1(pInt);

4      assert(temp1.use_count() == 1);

5      shared_ptr<int> temp2(pInt);

6      assert(temp2.use_count() == 1);

7 }      // temp1和temp2都离开作用域,它们都销毁pInt,会导致两次释放同一块内存

正确的做法是将原始指针赋给智能指针后,以后的操作都要针对智能指针了。参考代码如下:

1 {

2      shared_ptr<int> temp1(new int(5));

3      assert(temp1.use_count() == 1);

4      shared_ptr<int> temp2(temp1);

5      assert(temp2.use_count() == 2);

6 }      // temp1和temp2都离开作用域,引用次数变为0,指针被销毁。

另外,使用shared_ptr来包装this时,也会产生与上面类似的问题。考虑如下代码:

1 class A

2 {

3 public:

4         shared_ptr<A> Get()

5         {

6              return shared_ptr<A>(this);

7         }

8 }

9

10 shared_ptr<A> pA(new A());

11 shared_ptr<A> pB = pA->Get();

当pA和pB离开作用域时,会将堆上的对象释放两次。如何解决上述问题呢?C++ 11提供了如下机制:将类从enable_shared_from_this类派生,获取shared_ptr时使用shared_from_this接口。参考代码如下:

1 class A :public enable_shared_from_this<A>

2 {

3 public:

4         shared_ptr<A> Get()

5         {

6              return shared_from_this();

7         }

8 }

在多线程中使用shared_ptr时,如果存在拷贝或赋值操作,可能会由于同时访问引用计数而导致计数无效。解决方法是向每个线程中传递公共的week_ptr,线程中需要使用shared_ptr时,将week_ptr转换成shared_ptr即可。

转载     http://www.cnblogs.com/hujian/archive/2012/12/10/2810754.html

如有版权问题,请联系QQ    858668791

时间: 2024-11-08 05:59:14

C++ 11智能指针之shared_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

boost智能指针之shared_ptr和weak_ptr

std::auto_ptr很多的时候并不能满足我们的要求,比如auto_ptr不能用作STL容器的元素.boost的smart_ptr中提供了4种智能指针和2种智能指针数组来作为std::auto_ptr的补充. shared_ptr<boost/shared_ptr.hpp>:使用shared_ptr进行对象的生存期自动管理,使得分享资源所有权变得有效且安全. weak_ptr<boost/weak_ptr.hpp>:weak_ptr 是 shared_ptr 的观察员.它不会干

详解C++11智能指针

前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用. C++11智能指针介绍 智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象.当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏.C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用.该引用计数的内存在堆上分配.当新

【STL学习】智能指针之shared_ptr

前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择  几乎所有的程序都需要某种形式的引用计数智能指针,这种指针让我们不再需要为两个对象或更多对象共享的对象的生命周期而编写复杂的逻辑(写起来有点绕口),当被共享的对象引用计数降为0时,被共享对象被自动析构. 引用计数指针分为插入式(instrusive)和非插入式(non-instrusive)两种.前者要求它所管理的类提供明确的函数或数据成员用于

C++11智能指针

C成也指针,败也指针.确实,指针给程序员提供了很多便利和灵活性,但是不当的指针使用也会造成很多问题. Java和C#避免了指针(虽然C#中也能使用指针,但是估计很少有人这样做),其垃圾回收机制,给程序员减轻很多管理内存的负担. 为了带来指针更好的使用体验,C++中引入了智能指针的概念,其实质就是将指针的一些操作封装成类,程序员通过使用熟悉的指针运算符(-> 和 *)访问封装指针,该指针类通过运算符重载返回封装的原始指针. C++ 智能指针思路类似于C#等语言中创建对象的过程:创建对象后让系统负责

c++11 智能指针

如果在程序中使用new从堆(自由存储区)分配内存,等到不需要时, 应使用delete将其释放.c++引入了智能指针auto_ptr, 以帮助自动完成这个过程. c++11摒弃了auto_ptr,并新增了三种智能指针:unique_ptr, shared_ptr, weak_ptr. 一. auto_ptr, unique_ptr , shared_ptr 头文件:  #include <memory> 用法:  auto_ptr<double>  A(new double); un

一次测试测试(C++11)智能指针引用的崩溃结论

项目中用到了智能指针,但是要在智能指针指向的类中获取此类的shared_ptr指针传给其引用的类,结果出现了问题, 测试代码如下: (包括错误解释) 1 //测试 shared_ptr weak_ptr map<string,shared_ptr> 2 #include <stdio.h> //pinrtf ... 3 #include <string> //string ... 4 #include <map> 5 #include <memory&

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

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

智能指针(二):shared_ptr实现原理

前面讲到auto_ptr有个很大的缺陷就是所有权的转移,就是一个对象的内存块只能被一个智能指针对象所拥有.但我们有些时候希望共用那个内存块.于是C++ 11标准中有了shared_ptr这样的智能指针,顾名思义,有个shared表明共享嘛.所以shared_ptr类型的智能指针可以做为STL容器的元素 下面我们来瞧瞧shared_ptr具体是咋实现的.相较auto_ptr有下面几个不同的地方: 1.引进了一个计数器shared_count,用来表示当前有多少个智能指针对象共享指针指向的内存块 2