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\n", __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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d4b4de05a44a453532563d64473afa0e.html