【C++学习】标准库:内存管理(总结C++primer第十二章)

动态内存

  • 动态分配对象的生存期和它们在无关,只有显式地被释放时,这些对象才会被释放;
  • 为了解决动态对象能够被正确释放的问题,设置智能指针,当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它;
  • 内存分类:
    • 静态内存:保存局部static变量、类的static数据成员及全局变量,由编译器自动创建和销毁;
    • 栈内存:保存局部变量,由编译器自动创建和销毁;
    • 程序的自由空间(堆,heap):存储动态分配(程序运行时分配)的对象。

动态内存和指针

  • 直接动态内存管理的运算符:

    • new,在动态内存中为对象分配一个空间并返回一个指向该对象的指针
    • delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
  • 问题:

    • 忘记释放,内存泄漏
    • 过早释放,使用非法的引用或者指针。
  • 解决:两个智能指针,和一个伴随类,定义在头文件memory

    • shares_ptr,允许多个指针同时指向一个对象;
    • unique_ptr,独占一个对象;
    • 伴随类weak_ptr,它是一个弱引用。指向的是shared_ptr所管理的对象。
  • shared_ptr类

    • 智能指针实现的机制。依靠智能指针类里面的引用计数器成员,当进行拷贝时,引用计数增加;当一个局部ptr被销毁或者一个ptr被赋予新值时,引用计数器减少;当一个被引用对象的引用计数为0时,它的空间就会被自动释放

    • 智能指针是一个模板类,它的定义以及初始化方式如下:

      {
          shard_ptr<string> p1;//指向string对象的空指针
          shared_ptr<list<int>> p2;//指向int类型的list的空指针。
      }
      
    • make_shared函数:分配和使用动态内存的方法:

      {
          auto p1 = make_shared<int>(42);//p指向一个值为42的int类型。
          shared_ptr<string> p2 = make_shared<string>(10,'2');//p2指向内容为10个2的string类型。
          shared_ptr<int> p3 = make_shared<int>();//p3指向一个值初始化为0的int类型
      }
      
    • shared_ptr和unique_ptr都支持的操作

      操作名称相关介绍
      shared_ptr sp;空智能指针
      unique up;
      p将p作为一个条件,非0返回true
      *p解引用
      p->mem等价于(*p).mem
      p.get()返回与p指向同一个对象的内置指针。
      swap(p,q)交换指针的值
      q.swap(q)
    • shared_ptr独有的操作

      操作名称相关描述
      make_ptr(agrs)返回一个指向动态分配的类型为T的对象的shared_ptr。该对象用args进行初始化。
      shared_ptr p(q)进行拷贝初始化。q中的指针必须可以转换为T*pshared_ptr类型的指针。
      p = qp,q都是shared_ptr,并且它们所指向的类型必须可以进行相互转换。
      p.use_count()返回的是与p共享对象的智能指针的数量,可能很慢,主要用于调式。
      p.unique()如果p.use_count()的数量为1,返回的是true,否则返回的是false
  • 直接内存管理

    • 使用new关键字创建指针分配的空间是没有命名的,返回的是指针指向该对象;
    • 可以选择是否值初始化,const对象必须进行初始化(若定义默认构造函数的类类型可以隐式初始化);
    • delete销毁给定指向的对象,然后释放内存:
      • 不可以对同一个空间进行多次释放;
      • 只能对new关键字分配的内存或者空指针进行delete;
      • 由内置指针管理的动态内存在被显示释放前会一直存在;
    • 空悬指针:指向一块曾经保存数据对象但现在已经无效(指针被delete)的内存的指针。
  • shared_ptr和new的结合使用(智能指针及内置指针)

    • 可以用new返回的指针初始化(必须是直接初始化)智能指针:

      {
          shared_ptr<int> p = new int(12);
          //错误,对于内置类型对shared_ptr的初始化,只能是直接初始化,不能是拷贝。
          // 因为智能指针将会对该内置指针指向的空间进行接管。
          shared_ptr<int> p(new int(12));//正确
      
          //使用reset,用内置指针对智能指针赋值
          p.reset(new int(1024));
          // 使用显式地转换也可以。
          p = shared_ptr<int>(new int(12));
      }
      
    • 定义和改变shared_ptr的其他方法

      操作名称相关描述
      shared_ptr p(q);q是一个内置指针,p管理内置指针的空间。q必须是由new分配的,并且可以转换为T*
      shared_ptr p(u);p从unique_ptr中接管对象,将u置为空。也就是unique_ptr和shared_ptr之间的转换。
      shared p(q,d);同第一个操作,但使用可调用对象d代替delete
      shared_ptr p(p2,d)p2是shared_ptr p2类型的拷贝,区别就是使用d来代替delete
      p.reset()如果p是唯一指向其对象的shared_ptr,reset会释放这个对象。并将p置为空。
      p.reset(q)此时指向的是内置指针q
      p.reset(q,d)此时用d代替delete
    • 不要混合使用普通指针和智能指针,也不要使用get初始化另一个智能指针或为智能指针赋值;

    • 推荐使用make_shared而不是new

  • unique_ptr

    • 一个unique_ptr“拥有”它所指向的对象,即某个时刻只能有一个unique_ptr指向一个给定对象,可以认为它的引用计数只能为1;

    • 除了与shared_ptr相同的操作,还支持以下操作:

      操作名称相关描述
      unique_ptr u空的智能指针。使用delete来释放空间
      unique_ptr<T,D> uu会调用D代替delete
      unique_ptr<T,D>u(d)空的指针,hi用类型为D的d来重载delete
      u = nullptr释放u指向的空间,并置为空指针
      u.release()u放弃控制权,并返回一个内置指针。u置为空指针。没有释放空间
      u.reset()**释放空间,并且u置为空。**如果u为空则无需释放。
      u.reset(q)内置指针q。u释放所指向的空间,并且指向新的q。
      u.reset(nullptr)效果同u.reset()
    • unique_ptr不支持普通的拷贝或赋值,但可以通过调用release或reset将指针的所有权从一个非const的unique_ptr转移给另一个unique。

    • 可以拷贝或赋值一个将要被销毁的unique_ptr,如函数的返回值。

  • weak_ptr

    • 不会控制对象的生存期;

    • 只能用shared_ptr初始化weak_ptr;

      {
          auto p = make_shared<int>(42);
          weak_ptr<int> q(p);
      }
      
    • 由于是弱引用,它的引用不计入引用计数中,因此它可能是无效的,使用时需要进行判断,使用local

      {
          if (shared_ptr q = wp.local())
          {
              //保证q是有效的
          }
      }
      

动态数组

  • 解决一次为多个对象分配、释放内存的问题;
  • 大多数应用应使用标准库容器而不是动态分配的数组,使用容器更为简单、更不容易出现内存管理错误并且可能有更好的性能;
  • 具体参考动态数组

使用标准库:文本查询程序

  • 文本查询程序设计思路:
    • 利用vector存储文本中的每一行。
    • 利用istringstream对输入的每一行进行分解。
    • 利用set存储每一个单词出现的所有行号。
    • 利用map将每一个单词和它的set相互关联起来。
    • 使用共享数据,shared_ptr(设计两个类)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值