zoukankan      html  css  js  c++  java
  • (转)C++11里的智能指针

    1. std::auto_ptr有些违背c++编程思想. 已经被"不建议使用了".
    2. 下文转自:http://blog.csdn.net/lanergaming/article/details/24273419


    c#和java中有自动垃圾回收机制,.net运行时和java虚拟机可以管理分配的堆内存,在对象失去引用时自动回收,因此在c#和jva中, 
    内存管理不是大问题。c++语言没有垃圾回收机制,必须自己去释放分配的堆内存,否则就会内存泄露。
      我相信大部分c++开发人员都遇到过内存泄露的问题,而查找内存泄露的问题往往要花大量的精力。要解决这个让人头疼的问题可 
    以采取一些办法,最有效的办法是使用智能指针!使用智能指针就不会担心内存泄露的问题了,因为智能指针可以自动删除删除分 
    配的内存。

      智能指针是指向动态分配(堆)对象指针,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存 
    泄露。它的一种通用实现技术是使用引用计数。每次使用它,内部的引用计数加1,每次析构一次,内部引用计数减1,减为0时,删 
    除所指向的堆内存。

    c++11之前,c++没有内置智能指针,之前只能借助于boost的智能指针或者自己发明轮子。c++11现在内置的智能指针,使我们可以 
    很方便的使用智能指针了。c++11中的智能指针包括:

    • std::shared_ptr
    • std::unique_ptr
    • std::weak_ptr

    std::shared_ptr

    std::shared_ptr使用引用计数. 每一个shared_ptr的拷贝都指向相同的内存。 在最后一个shared_ptr析构的时候, 内存才会被释 
    放。
    我们看看shared_ptr如何使用吧。
    1.初始化

    //智能指针的初始化
    std::shared_ptr<int> p(new int(2));
    std::shared_ptr<int> p2 = p;
    std::shared_ptr<BaseConnector> m_connt = make_shared<Connector>(m_ios, m_strIP, m_port);

    通过构造函数、赋值函数或者make_shared函数初始化智能指针。
    智能指针初始化可以指定删除器

    复制代码
    void DeleteIntPtr(int* p)
    {
    delete p;
    }
    
    std::shared_ptr<int> p(new int, DeleteIntPtr);
    p的引用计数为0时会自动调用删除器DeleteIntPtr
    复制代码

    2.智能指针中的原始指针,通过get获取
    char* pData = pBuf.get();

    3.注意事项。智能指针虽然能自动管理堆内存,但是它有不少陷阱,使用时需要注意:

    1.不要把一个原生指针给多个shared_ptr管理

    int* ptr = new int;
    shared_ptr<int> p1(ptr);
    shared_ptr<int> p2(ptr); //logic error
    导致ptr被删除两次

    2.不要把this指针给shared_ptr
    3.不要在函数实参里创建shared_ptr 

    function ( shared_ptr<int>(new int), g( ) ); //有缺陷
    可能的过程是先new int,然后调g( ),g( )发生异常,shared_ptr<int>没有创建,int内存泄露
    shared_ptr<int> p(new int());
    f(p, g()); 
    4.对象内部生成this的shared_ptr  

    enable_shared_from_this 类,在该类中定了成员函数 shared_from_this() ,返回shared_ptr<T> 。这个函数仅在 shared_ptr<T> 的构造函数被调用之后才能使用。原因是 enable_shared_from_this::weak_ptr 并不在构造函数中设置(此处的构造函数指的是类型 T 的构造函数),而是在 shared_ptr<T> 的构造函数中设置(此处的构造函数指的是类型 shared_ptr<T> 的构造函数)。

    若不使用 shared_from_this() 成员函数,将this指针构造了一个shared_ptr,外面创建的对象本身的shared_ptr也管理了this资源,在析构时则会发生两次析构;

    复制代码
    class Y: public std::enable_shared_from_this<Y>
    {
    boost::shared_ptr<Y> GetSelf()
    {
    return shared_from_this();
    }
    };
    
    boost::shared_ptr<Y> spy(new Y)
    boost::shared_ptr<Y> p = spy->GetSelf(); //OK
    复制代码

    5.shared_ptr作为对象的成员时,小心因循环引用造成无法释放资源。

    复制代码
    struct A;
    struct B;
    struct A
    {
    std::shared_ptr<B> m_b;
    };
    
    struct B
    {
    std::shared_ptr<A> m_a;
    };
    
    std::shared_ptr<A> ptrA(new A);
    std::shared_ptr<B> ptrB(new B);
    ptrA->m_b = ptrB;
    ptrB->m_a = ptrA;
    复制代码

    ptrA和ptrB相互引用,离开作用域时引用计数都为1,导致内存没有被释放,解决办法是把A和B任何一个的成员变量改为weak_ptr
    解决办法是把A和B任何一个的成员变量改为weak_ptr

    struct B
    {
    std::weak_ptr<A> m_a;
    };

    ptrB->m_a不会增加A对象的引用计数,因此A对象离开作用域时,引用计数为0,m_b的引用计数减一,b离开作用域后引用计数由1减为0.

    std::weak_ptr
    弱引用指针,用来监视智能指针,不会使引用计数加1。在访问所引用的对象前必须先转换为 std::shared_ptr。

    用来表达临时所有权的概念:当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用

    来跟踪该对象。需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的std::shared_ptr 被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

    还可以用来避免 std::shared_ptr 的循环引用。

    复制代码
    std::weak_ptr<int> gw; 
    void f()
    {
    if (auto spt = gw.lock()) { // Has to be copied into a shared_ptr before usage
    std::cout << *spt << "
    ";
    }
    else {
    std::cout << "gw is expired
    ";
    }
    }
    
    int main()
    {
    {
    auto sp = std::make_shared<int>(42);
    gw = sp;
    f();
    }
    f();
    }
    输出
    42 
    gw is expired
    
    复制代码

     std::unique_ptr

    unique_ptr不会共享它的指针。 无法将它复制到另一个unique_ptr, unique_ptr只能移动。 这意味着内存资源的所有权将转移到新的unique_ptr和原始unique_ptr不再拥有它。
    int* p = new int;
    std::unique_ptr<int> ptr(p);
    std::unique_ptr<int> ptr1 = ptr; //不能复制,编译报错
    
    auto ptr2 = std::move(ptr); //转移所有权, 现在ptr那块内存归ptr2所有, ptr2成为无效的指针.

    智能指针是个好东西,使用它之后就不用担心内存释放、内存泄露的问题了,我的项目中都是用的智能指针,没有delete。

    智能指针使我们的程序更安全,除了循环引用会导致内存泄露之外,其他都很安全,可以放心使用。

  • 相关阅读:
    POJ 1426 Find The Multiple(数论——中国同余定理)
    POJ 2253 Frogger(Dijkstra变形——最短路径最大权值)
    POJ 3790 最短路径问题(Dijkstra变形——最短路径双重最小权值)
    POJ 3278 Catch That Cow(模板——BFS)
    HDU 1071 The area
    HDU 1213 How Many Tables(模板——并查集)
    POJ 1611 The Suspects
    light oj 1214 Large Division
    POJ 1258 Agri-Net(Prim算法求解MST)
    POJ 2387 Til the Cows Come Home(模板——Dijkstra算法)
  • 原文地址:https://www.cnblogs.com/xiaouisme/p/7498782.html
Copyright © 2011-2022 走看看