zoukankan      html  css  js  c++  java
  • C++智能指针

    C++智能指针

    智能指针与异常

    如果使用智能指针, 如果程序块过早的结束, 智能指针能保证在内存不再需要时进行释放. (特别是在有多个出口的函数中 -- 虽然应尽量避免设计这样的函数, 但凡事总有例外 -- 此时使用智能指针来自动释放内存是非常方便的)
    对于异常处理来说, 考虑下面两个函数, 当程序发生异常时, 智能指针也能正确的释放内存.
      void f3()
      {
        int* p = new int(10);
        throw "some error infomations";
        delete p;
      }

    void f4()
    {
        std::shared_ptr<int> sp = std::make_shared<int>(10);
        throw "some error infomations";
    }

     

    使用智能指针时的注意事项

    C++智能指针使用时需要注意的事项, C++11中已经废弃了 auto_ptr, 因此不再讨论其用法, 无特殊说明, 下面的事项对 auto_ptr 而言, 可能是不正确的.

    (1) 不要把一个原生指针给多个智能指针对象管理, 对所有的智能指针对象都成立

        int* p = new int(2);
        std::shared_ptr<int> sp0(p);
        std::shared_ptr<int> sp1(p); // 错误, 不能将同一原始指针对象给两个智能指针对象管理

    (2) 不要把 this 指针给智能指针对象, 对所有的智能指针对象(包括 auto_ptr)都成立, 下面的代码演示错误的使用方法  

            #define PRINT_FUN() printf("%s:%d
    ", __FUNCTION__, __LINE__)
            
            class CTest{
            public:
                CTest(){};
                ~CTest(){
                    PRINT_FUN();
                };
                void Run()
                {
                    m_sp = std::shared_ptr<CTest>(this); // 错误, 当 CTest 对象释放时也会释放 m_sp , 此时会再次 delete CTest 对象. (析构函数中的打印消息可以看出会出现一个对象两次调用析构函数.)
                }
            private:
                std::shared_ptr<CTest> m_sp;
            };
            
            std::shared_ptr<CTest> sp(new CTest());
            sp->Run();
            或者这样写
            CTest t;
            t.Run();    

      (3) 不要在函数实参里创建智能指针对象

    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) 处理不是 new 创建的对象要小心. 如果确实需要这样做, 需要智能指针传递一个删除器, 自定义删除行为.

        int* pi = (int*) malloc(4);
        shared_ptr<int> sp(pi); // shared_ptr 析构时将调用 delete. 使用 malloc 分配内存, 用 delete 释放显然不对.

      (5) 不要使用 new 创建一个智能指针对象.如 new shared_ptr<T> : 本来 shared_ptr 就是为了管理指针资源的, 不要又引入一个需要管理的指针资源shared_ptr<T>*

      (6) 使用 dynamic_pointer_cast 进行转换(C++11 中已废弃 shared_dynamic_cast)

                class B
                {
                public:
                    B(){};
                    virtual ~B(){};
                };
                class D : public B
                {
                public:
                    D(){};
                    virtual ~D(){};
                };
    
                std::shared_ptr<B> sp(new D);
                B* b = sp.get();
                D* d = dynamic_cast<D*>(b);
            正确用法:
                std::shared_ptr<B> spb(new D);
                std::shared_ptr<D> spd = std::dynamic_pointer_cast<D>(spb);

      (7) 不要 memcpy 智能指针对象

    shared_ptr<B> sp1(new B);
    shared_ptr<B> sp2;
    memcpy(&sp2, &sp1, sizeof(shared_ptr<B>)); //sp2.use_count()==1
    很显然,不是通过正常途径(拷贝构造,赋值运算),引用计数是不会正确增长的。

    (8) 智能指针对象数组的使用, 需要自定义释放器.

        shared_ptr 数组, std::shared_ptr<A> p(new A[10], std::default_delete<A[]>());
        std::unique_ptr<int[]>(new int[10], std::default_delete<int[]>());

      (9) 将智能指针对象作为函数参数传递时要小心, 如下面的代码, 当调用所在的表达式结束(即函数调用返回)时, 这个临时对象就被销毁了, 它所指向的内存也被释放.

          int* pa = new int(10); // 小心, 不是一个智能指针
          f(std::shared_ptr<int>(pa)); // 合法的, 但内存会被释放
          int a = *pa; // 错误, pa已经被释放, 但继续指向已经释放的内存, 从而变成了一个空悬指针, 现在试图访问 pa 的值, 其结果是未定义的
        应该这样使用:
          std::shared_ptr<int> sp(new int(10));
          f(std::shared_ptr<int>(sp)); // 调用拷贝构造函数, sp.use_count == 2

      (10) 当将一个智能指针对象(如 shared_ptr)绑定到一个普通指针时, 就将内存管理的责任交给了这个 shared_ptr. 此后就不应该使用内置指针来访问 shared_ptr 所指向的内存了.

      (11) 不能使用 delete 释放 get 返回的普通指针. get 函数的设计是为了向不能使用智能指针的代码传递一个普通指针, 应该减少 get 函数的调用.

      (12) 不要使用 get 返回的普通指针来初始化另一个智能指针, 或为另一个智能指针赋值. 显然如果这样做, 将导致两次释放相同的内存, 或者其中一个已经将内存释放, 但另一个还在使用.

    std::shared_ptr<int> sp = std::make_shared<int>(10);
    int* p = sp.get();
    {
      std::shared_ptr<int> sp(p);
    }
    int x = *sp;

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    webService 的使用
    前端框架——树形结构Ztree的使用
    vue使用问题总结(长期更新)
    yum安装配置MySQL数据库
    kworkerds挖矿木马
    zabbix 中文乱码
    GIT 仓库的搭建
    ELK 收集交换机日志(以华为交换机为例)
    Zabbix 邮箱告警(Python脚本)
    Tomcat8性能优化
  • 原文地址:https://www.cnblogs.com/diysoul/p/5930396.html
Copyright © 2011-2022 走看看