Effective C++第三章-资源管理-1

本文介绍了C++中智能指针的概念及其在资源管理中的应用,包括auto_ptr和shared_ptr的特点与区别,以及如何避免资源泄露并正确管理资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++的资源:

  • 动态分配内存
  • 文件描述器
  • 数据库连接
  • 网络sockets
  • 互斥锁
  • 图形界面中的字型和笔刷

以对象管理资源(又称为资源取得时机便是初始化时机,resource acquisition is initialization,RAII)

  1. 单纯依靠调用端执行delete语句是行不通的:

    一般调用端函数使用了函数(Create函数)返回的对象后,有责任删除之。但在以下情况下可能使得调用端函数来不及删除

    • 一个过早的return语句
    • 一个存在continue和goto语句的循环
    • 某个语句抛出异常
  2. 为确保Create函数返回的资源总是被释放,我们需要将资源放进对象内,当控制流离开调用端函数,该对象的析构函数会自动释放资源

    • 例1:auto_ptr

      • Header: < memory >

      Namespace: std

      • 是一个类指针对象,也就是智能指针,其析构函数自动对其所指对象调用delete
      void f()
      { std::auto_ptr<Investment> pInv(createInvestment());
      //利用create函数获得资源后立即放进对象pInv
      ...
      }//经由auto_ptr的析构函数自动删除pInv

      PS:对象被删除一次以上,会使程序出现“未定义行为”

      • 诡异的复制行为:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权,因此,受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它。
      std::auto_ptr<Investment> pInv1(createInvestment());   
      std::auto_ptr<Investment> pInv2(pInv1);//现在pinv2指向对象,pInv1被设为NULL
      pInv1 = pInv2; //现在pInv1指向对象,pInv2被设为NULL  
    • 例2:引用计数型智慧指针(reference-counting smart pointer,RCSP)shared_ptr

      • Header: < memory >

      Namespace: std::tr1

      • 也是智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。

        void f()
        {
        std::tr1::shared_ptr pInv(createInvestment());
        //利用create函数获得资源后立即放进对象pInv,shared_ptr是一个RCSP

        }//经由shared_ptr的析构函数自动删除pInv

      • RCSP无法打破环状引用(例如两个其实已经没被使用的对象彼此互指,因而好像处于“被使用”状态)。

      • 缺省行为是“当引用次数为0时删除其所指”,std::tr1::shared_ptr也允许指定“删除器”,是一个函数或函数对象,当引用次数为0时便被调用,删除器对std::tr1::shared_ptr构造函数而言是可有可无的地儿参数(此机能不存在于auto_ptr,它总是将其指针删除)

      class Lock{
      public:
          explicit Lock(Mutex* pm):mutexPtr(pm,unlock){}//以unlock函数为删除器
      private:
          std::tr1::shared_ptr<Mutex> mutexPtr;
      };
      • 复制
      std::tr1::shared_ptr<Investment> pInv1(createInvestment());   
      std::tr1::shared_ptr<Investment> pInv2(pInv1);//pinv2,pInv1指向同一对象
      pInv1 = pInv2; //pinv2,pInv1指向同一对象
    • 在auto_ptr和shared_ptr的析构函数内做delete而不是delete[],因此虽然可以通过编译,在动态分配而得的array身上使用是馊主意。

    • 在复制资源管理对象时,进行的是“深度拷贝”

    • 对于非heap-based资源,像auto_ptr和tr1::shared_ptr智能指针往往不适合作为资源掌管者

    PS : TR1(Technical Report 1)是一份规范,描述加入C++标准程序的诸多新技能大多数TR1机能是以Boost的工作为基础的。TR组件位于std::tr1命名空间中。大多数TR1机能是以Boost的工作为基础的。TR组件位于std::tr1命名空间中

在资源管理类中应提供对原始资源的访问

举例:

std::tr1::shared_ptr<Investment> pInv(createInvestment());
...
int fun(const Investment* pi);
...
int x = fun(pInv);//错误,所需参数是Investment*指针,但是传递的是tr1::shared_ptr<Investment>对象

解决方法:

  1. 显式转换(比较安全)

    tr1::shared_ptr和auto_ptr都提供一个get成员函数执行显式转换。也就是它会返回智能指针内部的原始指针(的复件):

    int x = fun(pInv.get());
  2. 隐式转换(对客户比较方便)

    • 同所有智能指针一样,tr1::shared_ptr和auto_ptr也重载指针取值操作符(operator->和operator*),它们允许隐式转换至底部原始指针:

      class Investment{
      public:
      bool isfun() const;
      ...
      };
      Investment* createInvestment();
      std::tr1::shared_ptr<Investment> pi1(createInvestment());
      bool isf1 = !(pi1->isfun());
      ...
      std::tr1::shared_ptr<Investment> pi1(createInvestment());
      bool isf1 = !((*pi1).isfun());
    • 提供隐式转换函数

      相关链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值