动态内存笔记

  1. 动态内存相对的是静态内存。指的其实就是申请堆空间。进程的内存空间从上到下为

    • 程序代码区:用来存储可执行的代码
    • 文字常量区:用来存储常量
    • 静态区:用来存储 全局变量(不在任何函数里面的变量,又包括了全局静态变量和非静态变量。),局部静态变量,类的static成员。相同点是这些都有全局的生存周期。这只是粗略的说法。静态区实际包括 两部分,一部分是初始化了的全局变量和局部静态变量,static成员。可以叫做data段。另外一部分是没有初始化的全局变量和局部静态变量,static成员。叫做bss段。
    • 环境变量等存储空间

    动态内存中对应的变量的生命周期很简单:当创建之时开启(使用new 或者 malloc),当释放之时结束(delete delete[] free)。

  2. 动态内存使用可能带来的问题:

    • 当忘记释放内存。指针被销毁,造成内存泄漏。
    • 当有指针指向一块内存,但是内存已经释放的时候,会出现野指针的问题。
  3. c++为了动态内存管理提供的措施。
    c++提供了两种智能指针,unique_ptr 和 shared_ptr 。weak_ptr 是一个伴随类。指向shared_ptr指向的对象。智能指针可以作为普通指针来用,包括 -> * 用于if判断 等操作

    • shared_ptr:
      • 可以使用拷贝构造函数,或者一般构造函数。
      • 可以进行赋值操作(右值可以是一个智能指针,不可以是普通指针)
      • 初始化的时候,不可以采用内置指针类型来直接赋值的操作。可以放在构造函数里面
      • 可以使用make_shared 函数来创建一个对象,然后初始化,将这个智能指针指向这个对象。参数其实就是对象的初始化参数。
      • shared_ptr有一个get函数,可以返回这个智能指针所包裹的内置指针。但是这个get得到的指针不要对其使用delete函数。否则,在智能指针推出delete的时候,就会因为对已经释放的内存delete而出错。也不要将这个指针绑定另外一个智能指针,因为这样的智能指针虽然是指向同一个内存,但是是独立创建的,没有关系,一旦另外一个智能指针销毁,导致对象销毁,那么另外一个智能指针销毁的时候就会出错。
      • shared_ptr内部有一个计数器,当赋值的时候,其原本的指向计数器就会-1,新的对象的计数器就会+1.当任何情况下,需要销毁指针的时候,就会调用析构函数。智能指针的析构函数会一方面 将引用计数器 -1.另一方面,如果引用计数器为0的时候,会调用引用对象的析构函数,将引用对象销毁。 在shared_ptr作为一个函数的返回值返回的时候,其先是进行赋值操作,计数器指针+1,然后销毁返回值,计数器-1.此时不会进行销毁对象操作。
      • 比如vector,其虽然是一个利用了动态内存的东西,但是当其推出其作用域的时候,也会将动态内存全部释放。为了实现vector的复制不是深复制,而是浅复制(浅复制有有利于数据共享的作用)。那么我们可以实现一个vector的包装,内部通过一个shared_ptr< vector >指针,来实现真正的动态内存存储。
      • 当我们使用的shared_ptr包裹的指针指向的对象 是一个没有析构函数的对象的时候,我们可以在定义shared_ptr的时候,传入一个deleter函数,来替代析构函数。而且这个可以保证资源被正确的关闭。
    • 使用原生的new 和 delete来进行管理。
      • new后面跟的就是类型名称。由于内存分配的时候,只需要知道类型即可,没有变量名称。数组,也可以认为是一种类型。此外,可以直接跟传统的初始化方法**()**的构造方式,也可以使用列表初始化。也可以不进行初始化。
      • new也可以动态分配一个const类型的变量。const在new 之后,类型之前。
      • delete可以接受的指针类型是 一个动态内存 的指针,或者是nullptr。其他类型的指针是未定义的。
    1. unique_ptr

      • 其特性为:在同一时刻,只允许一个指向这个对象的指针。当这个指针销毁的时候,相应的对象空间也被销毁。
      • 其初始化操作只允许使用一般构造函数,就是使用一个new指针的构造方式。不可以使用拷贝构造函数,也不允许使用赋值。
      • unique_ptr有release操作,可以抛弃原来的指针,并返回值返回,自身设置为null。有reset操作,无参数表示抛弃自身指针。有一个指针,表示设置为这个指针。
      • 当unique_ptr作为函数的形参的时候,不可以直接使用,因为不允许复制。可以使用引用。但是可以作为返回值返回,可以实现复制。因为马上就要销毁,这是知道的。
      • 可以向unique_ptr传递删除器。需要在类型里面也填上内容
    2. weak_ptr

      • 特征为 该指针很“弱”。当其指向一个对象的时候,该对象的引用计数(存在于shared_ptr中)不会增加。当其离开这个对象的时候,引用计数也不会减少。
      • 其初始化往往需要使用相对应的shared_ptr。指向shared_ptr也指向的对象。可以作为构造函数参数传递进去。也可以作为赋值的右端。
      • weak_ptr支持reset操作,可以将其置为空。use_count()可以返回指向的对象有几个shared_ptr。expired()只是这个对象是否因为没有shared_ptr而销毁,lock操作可以返回一个空shared_ptr(对象不存在了)或者是一个指向对象的shared_ptr
      • weak_ptr适用于那些对于对象只是起到监督作用的情况。可能偶尔会用到,但是不用也没关系。因此,不必为这个对象产生感知影响。只是再使用的时候造成感知。
    3. 动态数组

      • 动态数组其实就是 使用new来分配的数组类型的数据。其实最好使用标准库的容器来替代动态数组,更不容易出现错误。动态数组和内置类型的数组不同,其返回的是指向第一个元素的指针,而不是代表整个数组的指针。其实叫他数组是不贴切的。
      • 创建使用new Type[num] 即可。也可以直接进行初始化,也就是再[num]后面跟(初始化列表)。对每一个元素都使用这个参数来进行初始化。再新的标准里,也可以使用初始化器{}来进行初始化。如果不初始化,new会对类型进行默认的初始化。
      • [num]中的num可以是一个表达式,也可以为0.再内置类型的数组中,数组长度不可以为0.
      • 销毁动态数组 使用delete[] 运算符。使用delete[] 来删除一个单个元素指针,和使用delete来删除一个数组类型指针都是未定义的。可能会出错。
      • unique_ptr支持动态数组类型。定义之后,可以使用 下标运算符。
      • 由于动态数组的典型特征就是 将内存的申请和初始化连在一起。将内存的析构和内存的释放连在一起。这样会导致不够灵活。因此有allocator类型。分别有内存申请和初始化,析构和内存释放四个对应功能的函数,将过程分开。
      • allocator的创建需要指定数组的类型。即allocator< T > .allocate(n) construct(p, args):仅仅对p指向的元素, destroy§:仅仅对p指向的元素, deallocate(p, n):
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值