C++动态内存管理

来源:互联网 发布:少儿编程哪家好 编辑:程序博客网 时间:2024/06/09 16:31

1.C态内存管理细节

在说明C语言内存管理之前,要知道什么是内存,内存我个人认为可以理解为带有标签的盒子,所谓的带标签的盒子就像我们住的寝室一样有门牌号,盒子内只能存储固定类型的数据或变量,就如男生寝室只能住男生一样。那么c语言中有多少种盒子呢?有静态存储区、动态存储区、内部寄存器区域。我们通常定义的变量如果没有特意说明类型默认为自动变量类型存储在动态存储区

C语言自带了三个内存管理函数,包含在头文件stdlib.h中

1.malloc函数

调用形式为: ”’int p=(int )malloc(size)”’;size为要分配的内存的大小,malloc函数分配内存空间函数,当分配成功时返回分配的首地址(返回值为void类型),失败时返回零。
这里写图片描述

2.calloc函数

与malloc函数的功能相似也是 进行内存划分,但此函数可以一次划分m个相同大小的内存块。调用形式为:”’int p=(int )calloc(m,size)”’;size为每一块内存所占用的内存大小,m表示有多少这样的内存块。

3.realloc函数

从新分配有malloc或calloc函数分配的内存空间。
”’realloc()原型: void *realloc(void *mem_address, unsigned int newsize);”’
此函数的意义就是将*mem_address指向的内存从新分配为大小为newsize的新空间。
注意:使用realloc时要注意。realloc 返回的地址不一定是扩容之前的地址,也许是一块新的内存 ,新的地址,所以使用realloc时应该先对其地址进行判断,防止地址丢失。
这里写图片描述

4.free函数

malloc和calloc函数所开辟的内存空间都是在堆中开辟的,所以运行后要使用函数来释放内存。调用形式为free(p);//p为地址指针
注意:只要动态开辟了内存 就必须要有free,不然会导致内存泄漏。


2.C动态管理在C++中的缺陷引入C++动态内存管理

我们知道malloc只是单纯的开辟内存空间而不进行初始化,free只是将动态开辟的内存空间给释放了。
对于内置类型而言,用malloc/free开辟和释放内存没有一点问题,但是对于非内置类型来说,由于对象在创建的时候要调用构造函数进行初始化,而在对象在消亡的时候要调用析构函数进行一些清理工作,显然,malloc/free无法完成这些事情。
因此,c++中提供了new/delete两个操作符,用new在动态分配内存的时候调用构造函数进行初始化,delete在释放内存的时候自动调用析构函数进行清理。


3.C++动态内存管理基本语法和使用

C++通过new和delete动态管理内存。
new/delete动态管理对象。
new[]/delete[]动态管理对象数组。
这里写图片描述
new和delete一定要配对使用

4.C++提供的动态内存管理的底层实现及其接口operator new/delete/new[]/delete[]

C++中的new/delete与operator new/operator delete

new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。

new operator

(1)调用operator new分配足够的空间,并调用相关对象的构造函数
(2)不可以被重载

operator new

(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则如果有new_handler,则调用new_handler,否则如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则返回0
(2)可以被重载
(3)重载时,返回类型必须声明为void*
(4)重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)重载时,可以带其它参数
malloc/free和new/delete的区别和联系

1. 它们都是动态管理内存的入又。
2. malloc/free是C/C++标准库的函数,new/delete是C++操作符。
3. malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会
调用构造函数和析构函数进行初始化与清理(清理成员)。
4. malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类 型的大小,返回对应类型的指针。
5.


new做了两件事

  1. 调用operator new分配空间。
  2. 调用构造函数初始化对象。

delete也做了两件事

  1. 调用析构函数清理对象
  2. 调用operator delete释放空间

new[N]

  1. 调用operator new分配空间。
  2. 调用N次构造函数分别初始化每个对象。

delete[]

  1. 调用N次析构函数清理对象。(思考这里怎么N是怎么来的?)
  2. 调用operator delete释放空间。

5.new表达式

定位new表达式作用

1)placement new的作用就是:创建对象但是不分配内存,而是在已有的内存块上面创建对象。用于需要反复 创建并删除的对象上,可以降低分配释放内存的性能消耗。
2)定位new表达式(placement new expression,C++ primer P347),允许程序员将对象创建在已经被分配好的内存中,new表的式的形式如下:

new (place_address) type
new (palce_address) type (initializer-list)

place_address必须是个指针,指向已经分配好的内存。为了使用这种形式的new表达式,必须包含头文件。

定位new表达式不能调用delete删除 placement new的对象,需要人为的调用对象的析构函数,并且人为的释放掉占用的内存。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;class Array{public :    Array (size_t size = 10)        : _size(size)        , _a(0)    {        cout<<"Array(size_t size)" <<endl;        if (_size > 0)        {            _a = new int[ size];        }     }    ~Array()     {        cout<<"~Array()" <<endl;        if (_a)         {            delete[] _a ;            _a = 0;            _size = 0;        }     }private :    int* _a ;    size_t _size ; };void Test () {    // 1.malloc/free + 定位操作符new()/显示调用析构函数,模拟 new和delete 的行为     Array* p1 = (Array*) malloc(sizeof (Array));    new(p1) Array(100);    p1->~Array ();    free(p1 );    // 1.malloc/free + 多次调用定位操作符new()/显示调用析构函数,模拟 new[]和 delete[] 的行为    Array* p2 = (Array*) malloc(sizeof (Array)*10);    for(int i = 0; i < 10; ++i )     {        new(p2 +i) Array;    }    for(int i = 0; i < 10; ++i )     {        p2[i ].~Array();    }    free(p2 );}

6.delete[] 构函数调用细节剖析

在调用delete[]时 会按照下面流程图来调用函数
这里写图片描述