• 使用TR1的智能指针


    作为C++程序员,在没有智能指针,手动管理内存的蛮荒岁月里,可以说是暗无天日,痛苦异常。直到上帝说,还是要有光,于是智能指针进了标准。C++码农的日子总算好起来了。

    虽然一直鄙视着没有显式指针的语言,但是对其自动垃圾回收机制还是翘首以盼的,TR1的智能指针总算可以拿来慰藉下了。

    要使用VS2008 SP1的智能指针,我们需要加入头文件 memory.h(linux 下是 tr1memory.h),

    智能指针主要是 auto_ptr, shared_ptr, weak_ptr, unique_ptr ;其中模板auto_ptr是C++98提供的解决方案,C+11已将其摒弃。然而,虽然auto_ptr被摒弃,但它已使用了好多年.因为auto_ptr潜在的内存奔溃问题,所以不推荐使用它,本文也不准备讨论该指针.另外unique_ptr在Tr1中还未引入.

    Show me The Code

    namespace tr1SharedPoint
    {
    class Ap
    {
    public:
    	Ap(){
    		std::cout << "Ap Construct"<<std::endl;
    	};
    	~Ap(){
    		std::cout << "Ap Destruct"<<std::endl;
    	};
    	void pointerOutput(){
    		std::cout << "Use smart pointer to use me "<<std::endl;
    	}
    };
    typedef std::tr1::shared_ptr<Ap> spAp;
    }
    
    

    测试代码

    tr1SharedPoint::Ap *ap = new tr1SharedPoint::Ap;
    ap->pointerOutput();
    

    执行结果:

    Ap Construct
    Use smart pointer to use me
    

    可见,这里没有调用析构函数,内存泄漏就此发生了,需要在测试代码中 加入 delete ap补救之,也就是我们以前经常做的事情。

    • shared_ptr基本使用

    修改测试代码:

    tr1SharedPoint::spAp ap(new tr1SharedPoint::Ap);
    ap->pointerOutput();
    

    执行结果:

    Ap Construct
    Use smart pointer to use me
    Ap Destruct
    

    如此,一个指针的完美闭环就此产生了。我们不需要再手动添加delete语句,等到share_prt的作用域消失时,将自动调用Ap类的析构函数。很多局部锁的类也是如此构造的;

    • weak_ptr基本使用
      上面的代码 无法使用weak_ptr直接替换shared_ptr,因为weak_ptr是一种不控制指向对象生存期的智能指针,它指向一个shared_ptr管理的对象.调用lock()将返回一个shared_ptr对象,通过判断该值可以知道weak_ptr指向的内存是否已经被释放.
    typedef  std::tr1::weak_ptr<Ap> wpAp;
    tr1SharedPoint::wpAp wp = ap;//一个weak_ptr可以直接由一个shared_ptr赋值
    

    测试代码如下:

    tr1SharedPoint::wpAp wp;
    {
    	tr1SharedPoint::spAp ap(new tr1SharedPoint::Ap);
    
    	wp = ap;
    	if(wp.lock()){
    		std::cout << "ap not Destruct" <<std::endl;
    		std::cout <<"refence Num " <<wp.use_count() <<std::endl;
    	}
    
    	ap->pointerOutput();
    }
    	if(!wp.lock()){
    		std::cout << "ap IS Destruct" <<std::endl;
    		std::cout <<"refence Num " <<wp.use_count() <<std::endl;
    	}
    

    运行结果

    Ap Construct
    ap not Destruct
    refence Num 1
    Use smart pointer to use me
    Ap Destruct
    ap IS Destruct
    refence Num 0
    

    以上可知,weak_ptr能通过lock()判断其管理的shared_ptr是否释放,通过use_count()知道shared_ptr被引用的次数

    可是 只了解这么一点知识就可以了么?

    答案是,可能是的。如果你只是个总忘记调用delete的C++程序员。有兴趣的可以继续阅读.

    知道更多

    按上面的智能指针的用法,我们使用了new运算符,却没有显式的delete,造成了代码的不对称感,为了消除这种不对称,而又使用智能指针,我们最合适的方案是使用make_shared函数来声明内存的分配,可惜的是,TR1中并没有包含这个函数,限于本文的标准范围,我们只能通过boost等三方库来支持,可是如果使用了boost的内存语法,又没有必要使用TR1了.一个可能的方案就是把new给封装起来,眼不见为静.后期介绍C++11后,我们再来研究现在C++是如何完整的处理动态内存问题的.其实,这个问题在C++ Primer中有很详细的介绍.

    坚持只使用智能指针,就可以避免 1.忘记delete内存 2.使用已经释放掉的对象 3.同一块内存释放两次 这3类问题,对于一块内存,只有在没有任何智能指针指向它的情况下,智能指针才会自动释放它.

    • 在可能循环引用的类中,使用weak_ptr
      weak_ptr更常用的用法是解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。
    class A;
    class B;
    
    typedef std::tr1::shared_ptr<A> APtr;
    typedef std::tr1::shared_ptr<B> BPtr;
    typedef std::tr1::weak_ptr<A> AWeakPtr;
    typedef std::tr1::weak_ptr<B> BWeakPtr;
    
    class A {
    public:
      BWeakPtr b; // 注意这里
      ~A () {
        printf ("A released
    ");
      }
    
    };
    
    class B {
    public:
      AWeakPtr a; // 注意这里
      ~B () {
        printf ("B released
    ");
      }
    
      void output () {
        printf ("I'm B
    ");
      }
    };
    
    int main () {
      APtr a(new A());
      BPtr b(new B());
    
      a->b = b;
      b->a = a;
    
      BPtr b2(a->b.lock());
      b2->output();
    
      return 0;
    }
    

    运行结果

    I'm B
    B released
    A released
    

    可见,这里的A和B都能被正确释放了;

    • 使用 std::tr1::enable_shared_from_this 作为基类。比如:
    class A : public std::tr1::enable_shared_from_this<A>
    {
    public:
        std::tr1::shared_ptr<A> getSharedPtr() {
        return shared_from_this();
      }
    };
    
    

    当使用了 shared_ptr 的时候,我们可能需要在所有的地方都使用它,否则就不容易达到管理生存期的目的了。但有的时候,我们手头上只有对象的原始指针,比如在对象的函数内部,我们只有 this。这就迫切的需要一个功能:如何从对象的裸指针中,生成我们需要的 shared_ptr。

    有人可能会觉得这个简单,shared_ptr a(this); 不就行了么?很遗憾的告诉你,这样不行,会出问题。为什么呢?因为这里的 a,手中对 this 的引用计数只有 1,它无法知道其他地方智能指针对 this 这个指针(就是这个对象)的引用情况,因此当 a 的生命周期结束(比如函数返回)的时候,this 就会被它毫不留情的释放掉,其他地方的相关智能指针,手中拿着的该对象指针已经变成非法。因此,我们需要使用std::tr1::enable_shared_from_this 作为基类将类的this指针的引用导出来.

    参考阅读

  • 相关阅读:
    Lesson 43-44 Vacation Season is Approaching?
    Lesson 41-42 How would you respond?
    Lesson 37-38 Do you want to be a millionaire?
    Lesson 35-36 What did you forget?
    Lesson 33-34 Dieting
    保送
    陈老师搬书
    水题(原 USACO Mother's Milk)
    最大公约数和最小公倍数问题(luogu 1029)
    最大子矩阵(OJ 1768)
  • 原文地址:https://www.cnblogs.com/Stultz-Lee/p/9998527.html
Copyright © 2020-2023  润新知