Effective C++学习笔记(3)

目录

  • 条款13:以对象管理资源
  • 条款14:在资源管理类中小心copying行为
  • 条款15:在资源管理类中提供对原始资源的访问
  • 条款16:成对使用new和delete时要采取相同形式
  • 条款17:以独立语句将newed对象置入智能指针

条款13:以对象管理资源

    1. 在代码反复迭代过程中,可能不小心new一个对象之后,又在delete该对象之前,加入了一些return/continue代码,导致内存泄漏;又或者new和delete中间的代码部分出现了异常导致函数提前结束,进一步导致内存泄露。解决方法:可以创建资源管理对象,依赖对象来管理资源。当函数执行结束或者异常终止,其栈变量都将销毁。管理资源对象一般是以栈变量的形式存在,因此函数终止时会自动调用管理资源对象的析构函数,这样就可以在析构函数中调用delete释放被管理对象来达到管理资源的目的。
      (1)获得资源后立刻放进管理对象:“资源取得时机便是初始化时机”(RAII),因为我们几乎总是在获得一笔资源后于同一条语句内以它初始化某个管理对象。
      (2)管理对象运用析构函数确保资源被释放
      防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源,在析构函数中释放资源。
    1. 官方定义了多种智能指针来管理资源:
      (1)auto_ptr:auto_ptr被销毁时会自动删除它所指之物,注意不要让两个auto_ptr同时指向同一对象。若用copying函数复制它们,它们会变成null,而复制所得的指针获得该资源唯一管理权。该智能指针是C++旧版本的,建议不要使用这个。
      Effective C++学习笔记(3)_第1张图片
      (2)shared_ptr:该指针持续追踪有多少对象指向同笔资源(计数),并在无人指向它时自动删除该资源,类似垃圾回收,但存在“环状引用”的风险,weak_ptr智能指针可以解决环状引用。
      Effective C++学习笔记(3)_第2张图片

auto_ptr和shared_ptr均在其析构函数中做的是delete而非delete []。因此两者在管理动态数组时可能仍会造成内存泄漏。C11中unique_ptr可以直接管理动态数组;shared_ptr也可以通过自定义删除器来管理动态数组

条款14:在资源管理类中小心copying行为

对于非堆上开辟的资源,往往不适合用智能指针直接来管理,可能需要你建立自己的资源管理类。当两个资源管理对象copying操作时,可能会存在意想不到的情况发生,因此你需要对此情况进行应对:

    1. 禁止复制:可以像条款6一样,将copying操作设为private,或者继承private的copying操作的抽象类。
    1. 采用底层资源计数法:类似shared_ptr,多个管理资源对象可以指向同一个对象。当计数为0时,自动销毁被管理对象。有时候资源可能并不是只有生成和销毁,也有可能是“拥有”和“放手”。例如如果用资源管理类管理互斥锁对象,上锁时表示获取并拥有资源,而解锁时表示“放手”该资源,不一定需要detele销毁,可以利用shared_ptr自定义删除器实现。Effective C++学习笔记(3)_第3张图片
    1. 复制底部资源:执行深拷贝,生成资源的副本。
    1. 转移底部资源拥有权:类似auto_ptr,资源拥有权从被复制物转移到目标物

条款15:在资源管理类中提供对原始资源的访问

    1. APIs往往要求访问原始资源,所以每一个RAII class应该提供一个“取得所管理的原始资源”的办法。例如,用shared_ptr智能指针管理ABC类对象,有的函数必须让你传一个ABC类对象指针的实参,shared_ptr类提供一个get成员函数返回原始指针(显示转换),或者用操作符(operator->和operator*)隐式转换。
    1. 对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,隐式转换对客户比较方便(但有可能发生非故意类型转换)。
      Effective C++学习笔记(3)_第4张图片

Effective C++学习笔记(3)_第5张图片
Effective C++学习笔记(3)_第6张图片

条款16:成对使用new和delete时要采取相同形式

    1. 如果你在new表达式中使用[ ],必须在相应的delete表达式中也使用[ ]。如果在new表达式中不使用[ ],一定不要在相应的delete表达式中使用[ ]。
      Effective C++学习笔记(3)_第7张图片
    1. 对于喜欢用typedef的人来说,这一点更需要注意。如果typedef定义了一种数组类型,new的时候却不容察觉,以至于未采用delete[ ]。因此最好不要对数组形式做typedef,可用标准库中的容器替代。
      Effective C++学习笔记(3)_第8张图片

条款17:以独立语句将newed对象置入智能指针

在这里插入图片描述
上述函数的形参列表中由两个部分(三件事)组成,编译器产出一个函数调用码之前,必须首先核算将被传递的各个实参。三件事如下:
Effective C++学习笔记(3)_第9张图片
new Widegt肯定在调用智能指针构造函数之前,但是其他的执行顺序不一定。若执行以下顺序,调用priority时抛出异常,则申请的资源指针将会丢失,导致内存泄漏。
Effective C++学习笔记(3)_第10张图片
避免这种问题的方法:使用分离语句明确正确次序,(1)创建Widge,(2)将它置入智能指针内,再把智能指针传给processWidget函数即可
在这里插入图片描述

  • 以独立语句将newed对象存储于智能指针内。如果不这样做,一旦异常抛出,有可能导致难以察觉的资源泄漏

你可能感兴趣的:(c++,学习,java)