• (六)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
    ");
    
        }
    
        void StartThread()
    
        {
    
            //启动一个线程    
    
            ptrTh = new boost::thread(&MySelf::Run, this);
    
        }
    
        void Run()
    
        {
    
            //线程任务函数
    
            Sleep(5000);
    
            printf("stop thread
    ");
    
            Stop();
    
        }
    
        void Stop()
    
        {
    
            //删除自己
    
            myList.erase(shared_from_this());
    
        }
    
        ~MySelf()
    
        {
    
            printf("~MySelf
    ");
    
        }
    
    };
    
    
    
    void TestSharePtr()
    
    {
    
        boost::shared_ptr<MySelf> ptr1(new MySelf);
    
        //保存到list中
    
        myList.insert(ptr1);
    
        ptr1->StartThread();
    
    }
  • 相关阅读:
    火爆全网的合成大西瓜小游戏魔改版大全
    [Qt]cmake下Qt隐藏console的窗口
    c# WebBrowser控制台输出执行js后的网页内容
    好的编程习惯是减少bug最有效的方法
    创建线程 出现SIGSEGV crash
    linux下进程创建/僵尸进程/孤儿进程
    C++实现不可被继承的类
    程序并发概述
    C++ vector实现原理
    C++深拷贝和浅拷贝
  • 原文地址:https://www.cnblogs.com/timssd/p/5544676.html
Copyright © 2020-2023  润新知