引用计数智能指针std::tr1::shared_ptr与weak_ptr

C++ 11智能指针之shared_ptr
-- 本文来源于创世软件团队博客, 原文地址: http://www.cnblogs.com/hujian/archive/2012/12/10/2810754.html

头文件#include <memory>

 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即可。

 

智能指针 weak_ptr

http://blog.csdn.net/mmzsyx/article/details/8090849

weak_ptr:
 weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况.
用法:
 weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
 使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。
 weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr.
实例:
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
 shared_ptr<int> sp(new int(10));
 assert(sp.use_count() == 1);
 weak_ptr<int> wp(sp); //从shared_ptr创建weak_ptr
 assert(wp.use_count() == 1);
 if (!wp.expired())//判断weak_ptr观察的对象是否失效
 {
  shared_ptr<int> sp2 = wp.lock();//获得一个shared_ptr
  *sp2 = 100;
  assert(wp.use_count() == 2);
 }
 assert(wp.use_count() == 1);
 return 0;
}

获得this的shared_ptr
 weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己;对象使用weak_ptr观测this指针,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr共外界使用.
 这个解决方案被实现为一个惯用法,在头文件<boost/enable_shared_from_this.hpp>定义了一个助手类enable_shared_from_this<T>,它的声明摘要如下:
template<class T>
class enable_shared_from_this
{
public:
 shared_ptr<T> shared_from_this();
}
使用的时候只需要让像被shared_ptr管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr.例如:
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost;
using namespace std;
class self_shared: public enable_shared_from_this<self_shared>
{
public:
 self_shared(int n):x(n){}
 int x;
 void print()
 {cout<<" self_shared:"<<x<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
 shared_ptr<self_shared> sp = make_shared<self_shared>(314);
 sp->print();
 shared_ptr<self_shared> p = sp->shared_from_this();
 p->x = 1000;
 p->print();
 return 0;
}

注意:千万不能从一个普通对象(非shared_ptr)使用shared_from_this()获去shared_ptr,例如
self_shared ss;
shared_ptr<self_shared> p = ss.shared_from_this();//错误!
在运行时会导致shared_ptr析构时企图删除一个栈上分配的对象,发生未定义行为。

 

boost::shared_ptr是一个智能指针类,用于管理动态分配的对象。它提供了自动内存管理和资源释放的功能,可以避免内存泄漏和悬空指针的问题。\[1\] boost::shared_ptr的用法包括以下几个方面: 1. 创建shared_ptr对象:可以通过构造函数将指针传递给shared_ptr对象,也可以使用make_shared函数创建shared_ptr对象。 2. 使用shared_ptr对象:可以通过shared_ptr对象的get函数获取原始指针,通过*操作符访问指针指向的对象,通过->操作符访问对象的成员。 3. 共享所有权:多个shared_ptr对象可以共享同一个指针,当最后一个shared_ptr对象销毁时,会自动释放指针指向的对象。 4. 自定义删除器:可以通过构造函数或reset函数的第二个参数指定一个删除器,用于在shared_ptr对象销毁时执行特定的清理操作。 5. 避免循环引用:当存在循环引用时,可以使用weak_ptr来打破循环引用,避免内存泄漏。 boost::shared_ptr的实现机制是通过引用计数来管理对象的生命周期。每个shared_ptr对象都有一个引用计数,当有新的shared_ptr对象指向同一个指针时,引用计数加1;当shared_ptr对象销毁时,引用计数减1。当引用计数为0时,表示没有任何shared_ptr对象指向该指针,此时会自动释放指针指向的对象。 使用boost::shared_ptr需要注意以下几点: 1. 避免在多线程环境下同时访问同一个shared_ptr对象,需要进行适当的线程同步。 2. 不要将原始指针和shared_ptr混合使用,避免出现悬空指针或重复释放的问题。 3. 避免循环引用,使用weak_ptr来打破循环引用。 4. 注意使用shared_ptr的成员函数和操作符,如reset、swap、==、!=等。 关于boost::shared_ptr的更多详细信息,可以参考boost官方文档\[3\]。同时,还可以了解std::tr1::shared_ptr和boost::shared_ptr之间的差异和使用方式\[4\]。 #### 引用[.reference_title] - *1* *2* *3* [有关智能指针shared_ptr)的讨论](https://blog.csdn.net/weixin_30236595/article/details/96687717)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值