首先来展示下内存区域划分图
这里就不介绍堆栈和数据代码区域了,相信大家都非常熟悉了,简单谈一下内存映射段
内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信
这里提一下大家总是分不清楚的sizeof和strlen
sizeof 和 strlen的区别
-
sizeof是一个运算符(部分操作时不添加不尾缀括号),其作用是返回一个对象或者类型在内存中所占的字节
-
strlen是C语言中的库函数,依赖于<string.h>头文件,其作用是求字符串的实际长度,方法是从开始直到遇到第一个'\0'结束
函数原型unsigned int strlen(char* s)
数组做sizeof的参数不退化,传递给strlen就退化为指针了
eg:
char* ss = "0123456789";
sizeof(ss); 4
sizeof(*ss); 1
strlen(ss); 10
c语言中动态内存管理方式
malloc
void* malloc(size_t size)
calloc
void* calloc(size_t size, int num)
calloc会将申请的内存大小全部初始化为0
realloc
void* realloc(void* ptr,size_t size)
-
realloc的功能是将ptr所指向的空间进行调整大小到Size大小的字节数
-
如若ptr传入 的值为null则realloc的功能会和malloc相同
-
newsize和oldsize对比,如若大不了多少,则返回的地址还为原地址,否则重新分配newsize的内存,进行拷贝操作,然后释放旧空间
malloc工作原型:https://blog.csdn.net/mmshixing/article/details/51679571
此处需要知道malloc在分配空间时会数据区在之前添加一个meta区记录数据块的元信息(数据区大小、空闲标志位、指针等)
c++语言内存管理方式
先看三个例子的区别
int* ptr1 = new int;
int* ptr2 = new int(10);//动态申请一个int类型的空间并初始化为10
int* ptr3 = new int[10];//动态申请10个int类型的空间
new的原理:
-
调用operator new(系统全局函数)函数申请空间
-
在申请的空间上执行构造函数,完成对象的构造
delete的原理:
1.在空间上执行析构函数,完成对象中资源的清理工作
2.调用operator delete(系统全局函数)函数释放对象的空间
new T[N]的原理:
1.调用operator new[]函数,实际调用operator new函数完成N个对象空间的申请
2.在申请的空间上执行N次构造函数
void* operator new[ ](size_t size = N * sizeof(T) +4)//加4与否取决于T类是否提供析构函数
operator new(size)
delete[]的原理
1.在释放的对象空间上执行N次析构函数,完成N个对象中资源的a清理(从后往前)
2.调用operator delete[]释放空间,实际调用operator delete函数完成N个对象空间的申请
在空间内上文提到的4个字节当中取对象的个数N,调用N次析构函数
void operator delete[ ] (void* p)
operator delete(p)
free(p)
new/delete new[]/delete[] 要成套来使用 否则可能会造成崩溃或者内存泄漏(与析构处理有关)
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功直接返回,失败则尝试执行空间不足的应对措施,如果应对措施用户设置了,则继续申请否则抛异常
operator delete:该函数最终是通过free来释放空间的
operator new( )/operator delete( ) 用户可以自己实现
返回值必须是void* , 且首参数必然为size_t size
malloc/free & new/delete 区别
1.maollc/free是函数,new/delete是操作符
2.new申请的空间可以初始化,malloc不行
3.malloc的返回值是void*,所以需要计算空间大小并传递且使用时必须更改类型,new不需要
4.malloc申请失败返回NULL,new需要捕获异常
5.malloc申请的空间一定在堆上,而new不一定,因为operator new可能会存在重载
6.new/delete比malloc/free的效率稍微低点,因为new/delete的底层封装了maolloc/free
7.malloc/free只能申请内置类型的空间,不能申请自定义类型的空间,因为其不会调用构造与析构函数
这里普及一个概念,因为我这次总结知识点时第一次看到内置类型这个关键词
内置类型:C++定义饿了一套包括算术类型(字符型,整型,bool型,浮点型)和空类型(函数运行完成之后不返回任何数值)在内的基本数据类型
定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
void Text()
{
//此时pt指向的只是一个和Test对象有着相同大小的一段空间,因为并没有实现构造函数
//所以不能说pt就是指向了一个Text对象
Test* pt = (Test*)malloc(sizeof(Test));
//如果Test对象的构造函数需要传参时这里应当传参
new(pt) = Test;
delete pt;
}
怎么禁止一个函数的拷贝构造函数:
1.在私有里声明拷贝构造函数(C++98)
2.Test(const Test& t ) = delete
问题:只在堆/栈上创建一个对象?
堆: 私有化声明拷贝构造和构造函数,提供一个静态成员函数完成堆上创建对象
栈: 1.屏蔽(私有化)掉new的功能(operator new/delete)
//但全局作用域里还可以创建对象
2.私有化声明构造函数和拷贝构造,提供一个静态成员函数创建一个临时对象返回
//此方法创建了多个临时对象,资源浪费
创建对象的两种方式:
1.静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数;
2.动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。