当前位置: 代码迷 >> 综合 >> C++ primer笔记----动态内存
  详细解决方案

C++ primer笔记----动态内存

热度:42   发布时间:2023-12-13 12:55:35.0

1、 对象生命周期:全局对象在程序启动时分配,在程序结束时销毁。局部自动对象,当我们进入其定义所在程序块时被创建,在离开块时被销毁。局部static对象在第一次使用前分配,在程序结束时销毁

2、除了static和自动对象外,C++还支持动态对象的分配。动态分配的对象的生存期与它们在哪里创建无关,只有被显示的释放时,这些对象才会被销毁

3、动态对象的释放是编程中极其容易出问题的地方,为了安全使用动态对象,标准库定义了两个智能指针类型来管理动态分配对象,当一个对象应该被释放时,指向它的智能指针可以确保自动释放它

4、静态内存:保存局部static对象、类static对象、定义在任何函数之外的对象,由编译器自动创建和销毁。栈内存:保存定义在函数之内的非static对象,栈对象仅在定义的程序块运行时才存在

5、除了静态内存和栈内存,每个程序还拥有一个内存池,这部分内存被称为自由空间或堆,程序用堆来存储动态分配的对象:在程序运行时分配的对象,其生存周期由程序来控制,也就是说,当动态对象不再使用时,我们必须显式的销毁:必须正确的管理动态内存

6、C++中动态内存的管理是通过一对运算符来完成的,new:在动态内存中为对象分配空间并返回一个指向该对象的指针。delete:接受一个动态对象的指针,销毁该对象,并释放与之关联的内存

7、忘记释放内存:内存泄漏,在尚有指针引用内存的情况下释放了内存,就会产生引用非法内存的指针

8、为了更安全的使用动态内存,新标准库定义了两种智能指针类型来管理动态对象,头文件为memory,智能指针的主要作用就是自动释放所指向的对象,shared_ptr类型允许多个指针指向同一对象,unique_ptr类型则独占所指向对象

9、智能指针的使用方式与内置类型指针相似,解引用也是返回所指向对象,若在条件判断中使用,检测其是否为空

10、make_shared()函数:最安全的分配和使用动态内存的方法,此函数在动态内存中分配一个对象并初始化它,返回指向该对象的shared_ptr,头文件为memory

每个shared_ptr都有一个关联的计数器,称为引用计数,个人理解就是该对象被引用的次数,拷贝情况下会递增:
1:用一个shared_ptr初始化另一个shared_ptr(拷贝)
2:将一个shared_ptr传递给一个函数当参数,值传递(拷贝)
3:作为函数的返回值,(返回的是自身的拷贝,也就是活引用的次数+1)

计数器递减情况:
1:给shared_ptr赋予一个新值(也就是说自身指向了另外一个地址,原来指向的对象已经没有引用者,则会自动释放)
2:一个shared_ptr离开其作用域时,会被销毁(递减)

当一个shared_ptr的计数器变为0,他就会自动释放自己所管理的对象,前提是其指向的对象只有一个引用者。

11、当指向一个对象的最后一个shared_ptr被销毁时,该对象会被自动销毁:利用析构函数,会递减该对象的引用计数,当引用次数变为0,会销毁该对象,并释放它占用的内存

12、相关联内存是否销毁:所有指向该内存的shared_ptr对象都被销毁,也就是计数器为0

13、使用动态内存的原因:让多个对象共享相同的底层数据。也就是说拷贝的情况虽然发生,但是并不是元素的拷贝,而是将本身的指向拷贝给另一个指针对象,让这一个对象也指向自己所指向的对象,这样在本身释放以后,还有另一个对象指向自身原来所指向的对象。

14、new和delete相对于智能指针来说非常容易出错,最好使用智能指针来管理动态内存

15、在自由空间分配的内存是无名的,因此new无法为其分配对象命名,而是返回指向该对象的指针

16、默认情况下,new分配的对象是默认初始化的,这就说明内置类型或者组合类型将是未定义的(l例如:int,会指向一个为初始化的int),类类型对象将用默认构造函数进行初始化(例如string,会产生一个空string)。

17、建议使用值初始化(在最后加一对小括号即可),值初始化的内置类型对象有着良好定义的值

18、auto只有当括号中只有单一参数时可以使用,可以使用new分配const对象

19、delete完成两个操作:销毁给定指针所指向的对象,释放对应的内存,delete的参数必须是指向动态分配的对象或是一个空指针。

20、内置类型指针管理的动态内存在被显式的释放前一直都会存在,因为内置类型与类类型不同,虽然内置类型的指针会在离开作用域后被销毁,但是其内存依然存在

21、同一块内存释放两次:两个内置类型的指针指向同一块自由空间分配的内存,在对一个指针进行delete之后,其指向的内存也会被释放,若再对第二个指针进行delete,会造成自由空间破坏

22、忘记使用delete,使用已经释放掉的对象都是经常发生的(使用new和delete时),所以尽可能的使用智能指针

23、在很多机器上,即使delete了某个内置类型的指针(也就是说释放了对应的内存空间),虽然指针已经无效,但是其仍然保留这释放空间的对应地址,变成了空悬指针,也就是说我们要保留指针,可以将其置为空指针

24、理解变量的销毁与其内存的释放之间的关系:内置类型的指针在离开作用域时,本身会被销毁,但是其指向的内存空间什么都不会发生,必须以显式的delete进行释放空间。智能指针在离开作用域时,本身也会被销毁,并且计数器减一,当其计数器为0且只有一个智能指针指向该对象时,该对象的内存空间会被释放。如若用智能指针的get()函数得到的一个内置指针来初始化一个临时的智能指针,一旦该内置指针被释放,指向的内存也会被释放,原来的智能指针就会变成空指针

25、永远不要用get初始化另一个智能指针或是给智能指针赋值,只有在确定代码不会delete指针的情况下,才能使用get

26、将一个新的指针赋给shared_ptr:利用reset()函数,会更新计数。

27、如果在new和delete之间发生了异常,且异常未被捕获,则该内存就永远不会被释放!(非常危险!!!),而智能指针只要离开作用域,计数器减一,则随着智能指针被销毁,该块内存也会被释放,这就说明在实际使用过程中应使用shared_ptr来防止内存泄漏

28、正确的使用智能指针:
1:不使用相同的内置指针值初始化多个智能指针
2:不delete get()返回的指针
3:不使用get()初始化或reset另一个只能指针
4:当你使用的智能指针管理的资源布氏new分配的内存,记住传递一个删除器

29、unique_ptr拥有其所指向的对象,属于一一对应关系,unique_ptr被销毁时,其对象也会被销毁,unique_ptr不支持拷贝和赋值,必须采用直接初始化的方式,当我们定义一个unique_ptr时,必须将其绑定到一个new返回的指针上

30、可以使用release():放弃对指针的控制权,返回指针,并将其置为空,和reset():如果提供了内置指针q,令u指向这个对象,否则将u置空,将指针的所有权转移,但并没有释放内存

31、在unique_ptr快要被销毁时,可以进行拷贝:返回unique_ptr指针,这是一种特殊的拷贝

32、weak_ptr:不控制所指向对象生命周期的智能指针,使用时必须进行判断对象是否存在

33、大多数的应用应该使用标准库容器,而不是使用动态分配的数组

34、用new分配的动态数组会返回一个元素类型的指针,而并未得到数组类型的对象

35、动态数组并不是数组类型,不能调用begin()和end()函数

36、释放动态数组时,需要在指针名前加 [ ] ,数组中的元素按照逆序销毁

37、字符串字面常量不同于普通的局部变量,具有static duration lifetime,这整个程序的生命周期中都将存在

38、new将内存分配与对象构造组合在了一起,而allocator将内存分配和对象构造分离,它提供一种类型感知的内存分配方法,它分配的内存是原始的、未构造的

39、利用allocator分配内存之后。必须在经过construnct进行构造对象,两个参数分别为:创建对象位置的指针,元素类型的值

40、对构造后的元素进行destory操作,销毁对象,deallocator

  相关解决方案