(六)boost库之内存管理shared_ptr

(六)boost库之内存管理shared_ptr

1、shared_ptr的基本用法

    boost::shared_ptr<int> sp(new int(10));     //一个指向整数的shared_ptr
    assert(sp.unique());                        //现在shared_ptr是指针的唯一持有者
    boost::shared_ptr<int> sp2 = sp;            //第二个shared_ptr,拷贝构造函数
    assert(sp == sp2 && sp.use_count() == 2);   //两个shared_ptr相等,指向同一个对象,引用计数为2
    *sp2 = 100;                                 //使用解引用操作符修改被指对象
    assert(*sp == 100);                         //另一个shared_ptr也同时被修改
    sp.reset();                                 //停止shared_ptr的使用,引用计数减一
    assert(!sp);                                //sp不再持有任何指针(空指针)
    assert(sp2.use_count() == 1);               //sp2引用计数变为1
    sp.reset(new int(20));                      //sp管理一个新对象
    assert(*sp == 20);

2、应用于标准容器

有两种方式可以将shared_ptr应用于标准容器(或者容器适配器等其他容器)。

一种用法是将容器作为shared_ptr管理的对象,如shared_ptr<list<T> >,使容器可以被安全地共享,用法与普通shared_ptr没有区别,我们不再讨论。

另一种用法是将shared_ptr作为容器的元素,如vector<shared_ptr<T> >,因为shared_ptr支持拷贝语义和比较操作,符合标准容器对元素的要求,所以可以实现在容器中安全地容纳元素的指针而不是拷贝。

标准容器不能容纳auto_ptr,这是C++标准特别规定的(读者永远也不要有这种想法)。标准容器也不能容纳scoped_ptr,因为scoped_ptr不能拷贝和赋值。标准容器可以容纳原始指针,但这就丧失了容器的许多好处,因为标准容器无法自动管理类型为指针的元素,必须编写额外的大量代码来保证指针最终被正确删除,这通常很麻烦很难实现。

存储shared_ptr的容器与存储原始指针的容器功能几乎一样,但shared_ptr为程序员做了指针的管理工作,可以任意使用shared_ptr而不用担心资源泄漏。

#include <boost/make_shared.hpp> 
int main()  
{      
    typedef vector<shared_ptr<int> > vs;    //一个持有shared_ptr的标准容器类型      
    vs v(10);                               //声明一个拥有10个元素的容器,元素被初始化为空指针       
    int i = 0;      
    for (vs::iterator pos = v.begin(); pos != v.end(); ++pos)      
    {          
        (*pos) = make_shared<int>(++i);     //使用工厂函数赋值          
        cout << *(*pos) << ", ";            //输出值      
    }      
    cout << endl;       
    shared_ptr<int> p = v[9];      
    *p = 100;      
    cout << *v[9] << endl;  
} 

这段代码需要注意的是迭代器和operator[]的用法,因为容器内存储的是shared_ptr,我们必须对迭代器pos使用一次解引用操作符*以获得shared_ptr,然后再对shared_ptr使用解引用操作符*才能操作真正的值。*(*pos)也可以直接写成**pos,但前者更清晰,后者很容易让人迷惑。vector的operator[]用法与迭代器类似,也需要使用*获取真正的值。

3、使用助手类enable_shared_from_this

为什么要使用enable_shared_from_this,或许你对这个类感到很迷惑,先看看下面这种情况:

class MyPoint
{
public:
    MyPoint(){std::cout << "MyPoint" << std::endl;}
    ~MyPoint(){std::cout << "~MyPoint" << std::endl;}
    //返回this的函数
    boost::shared_ptr<MyPoint> GetPoint()
    {
        return boost::shared_ptr<MyPoint>(this);   //错误,将返回一个新的引用计数
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    boost::shared_ptr<MyPoint> p1(new MyPoint);
    boost::shared_ptr<MyPoint> p2 = p1->GetPoint();
    std::cout << p1.use_count() << "," << p2.use_count() << std::endl;  //输出引用计数情况
    p1.reset();          //内存将被释放
}

我们得到的答案将是:

MyPoint 
1,1 
~MyPoint

怎么正确的返回this呢,那么就需要借助enable_shared_from_this了,引入enable_shared_from_this的原因是可以实现返回值为指向该类本身的shared_ptr

正确的写法应该是这样的:

class MyPoint : public boost::enable_shared_from_this<MyPoint>
{
public:
    MyPoint(){std::cout << "MyPoint" << std::endl;}
    ~MyPoint(){std::cout << "~MyPoint" << std::endl;}
    //返回this的函数
    boost::shared_ptr<MyPoint> GetPoint()
    {
        return shared_from_this();
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
     boost::shared_ptr<MyPoint> p1(new MyPoint);
     boost::shared_ptr<MyPoint> p2 = p1->GetPoint();
     std::cout << p1.use_count() << "," << p2.use_count() << std::endl;  //输出引用计数情况
     p1.reset();          //内存将被释放
}

4、定制删除器

当你在使用windows API函数进行编程时,你最烦的或许就是怎么保证申请的内核对象是否关闭,考虑一下代码:

    int *p = (int*) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(p) );
    //业务处理
    //......
    HeapFree( GetProcessHeap(), 0, p );

对象不能通过delete来删除,而是一个释放函数,shared_ptr能否胜任呢,答案是肯定的。

    int *p = (int*) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(p) );
    //此处使用了lambda表达式,需要vs2010或更高版本的支持
    boost::shared_ptr<int> ptr(p, [](int *p){HeapFree( GetProcessHeap(), 0, p );});

5、综合应用示例

下面实现一个线程类,在线程运行结束时,能够自行清理自己的内存

#include <set>
#include <Windows.h>
#include <boost/thread.hpp>
class MySelf;
std::set< boost::shared_ptr<MySelf> > myList;
boost::thread *ptrTh;
class MySelf: public boost::enable_shared_from_this<MySelf>
{
public:
    MySelf()
    {
        printf("MySelf\n");
    }
    void StartThread()
    {
        //启动一个线程
        ptrTh = new boost::thread(&MySelf::Run, this);
    }
    void Run()
    {
        //线程任务函数
        Sleep(5000);
        printf("stop thread\n");
        Stop();
    }
    void Stop()
    {
        //删除自己
        myList.erase(shared_from_this());
    }
    ~MySelf()
    {
        printf("~MySelf\n");
    }
};

void TestSharePtr()
{
    boost::shared_ptr<MySelf> ptr1(new MySelf);
    //保存到list中
    myList.insert(ptr1);
    ptr1->StartThread();
}
时间: 2024-08-04 22:08:12

(六)boost库之内存管理shared_ptr的相关文章

详解Boost库智能指针(shared_ptr &amp;&amp; scoped_ptr &amp;&amp; weak_ptr )

我们先来解释一下什么叫智能指针? 智能指针是利用RAII(在对象的构造函数中执行资源的获取(指针的初始化),在析构函数中释放(delete 指针):这种技法把它称之为RAII(Resource Acquisition Is Initialization:资源获取即初始化))来管理资源. 其本质思想是:将堆对象的生存期用栈对象(智能指针)来管理.也就是当new一个堆对象的时候,立刻用智能指针来接管,具体做法是在构造函数中进行初始化(用一个指针指向堆对象),在析构函数调用delete来释放堆对象.由

linux, windows编译安装 boost库 (boost 1.56)

要用到 boost库,基础设施建设...做个记录 1.0  linux : 系统环境 [email protected]:~# cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=12.04 DISTRIB_CODENAME=precise DISTRIB_DESCRIPTION="Ubuntu 12.04 LTS" [email protected]-B85M-DS3H:~# uname -a Linux melos1305-

redis源码解析之内存管理

zmalloc.h的内容如下: 1 void *zmalloc(size_t size); 2 void *zcalloc(size_t size); 3 void *zrealloc(void *ptr, size_t size); 4 void zfree(void *ptr); 5 char *zstrdup(const char *s); 6 size_t zmalloc_used_memory(void); 7 void zmalloc_enable_thread_safeness(v

C++ Primer 学习笔记_56_STL剖析(十一)(原boost库):详解智能指针(unique_ptr(原scoped_ptr) 、shared_ptr 、weak_ptr源码分析)

注意:现在boot库已经归入STL库,用法基本上还和boost类似 在C++11中,引入了智能指针.主要有:unique_ptr, shared_ptr, weak_ptr. 这3种指针组件就是采用了boost里的智能指针方案.很多有用过boost智能指针的朋友,很容易地就能发现它们之间的关间: std boost 功能说明 unique_ptr scoped_ptr 独占指针对象,并保证指针所指对象生命周期与其一致 shared_ptr shared_ptr 可共享指针对象,可以赋值给shar

Boost库中的智能指针 shared_ptr智能指针

shared_ptr智能指针的意思即:boost::shared_ptr是可以智能的管理动态分配的内存资源,几个智能指针可以同时共享一个动态分配的内存的所有权. 下面我们通过一个例子来学习一下它的用法: 注 :使用shared_ptr智能指针,要加入#include <boost/shared_ptr.hpp>头文件 class example { public: ~example() { std::cout <<"It's over\n"; } void do

boost库使用:仿SGI-STL实现的一个树节点内存allocator

1 ////////////////////////////////////////////////////////////////////////// 2 //code by hzs 3 //email: [email protected] 4 //Last modified: 2014-5-18 21:05 5 ////////////////////////////////////////////////////////////////////////// 6 7 #ifndef _TRE

boost库学习之 shared_ptr

shared_ptr与scoped_ptr都包装在堆上分配的动态对象,都重载了*和->操作符以模仿原始指针行为,但shared_ptr实现的是引用计数型的智能指针,当没有代码使用时计数为0,此时释放被包装的动态分配的内存. shared_ptr可以被自由地拷贝和赋值.shared_ptr可以安全地放到标准容器中. 引用<boost程序库完全开发指南>中的话:"shared_ptr非常有价值.非常重要.非常有用." shared_ptr有多种形式的构造函数,应用于各种可

boost的内存管理

smart_ptr raii ( Resource Acquisition Is Initialization ) 智能指针系列的都统称为smart_ptr,包括c++98标准的auto_ptr 智能指针是一个类,通过重载->和*完成类似原始指针的操作.不过因为是类,所以可以做比如内存管理.线程安全之类的工作 智能指针均是自动管理内存,不需要显示调用delete scoped_ptr 与auto_ptr最大的不同,是私有化构造和拷贝构造,使操作权不能转让,所以有强作用域属性,而且指针类自己负责释

操作系统思考 第六章 内存管理

第六章 内存管理 作者:Allen B. Downey 原文:Chapter 6 Memory management 译者:飞龙 协议:CC BY-NC-SA 4.0 C提供了4种用于动态内存分配的函数: malloc,它接受表示字节单位的大小的整数,返回指向新分配的.(至少)为指定大小的内存块的指针.如果不能满足要求,它会返回特殊的值为NULL的指针. calloc,它和malloc一样,除了它会清空新分配的空间.也就是说,它会设置块中所有字节为0. free,它接受指向之前分配的内存块的指针