1.C++内存分区
C++内存分区:代码区:存放函数体的二进制代码,由操作系统管理
全局区:存放全局变量静态变量和常量。
栈区:编译器分配,存放函数的参数值和局部变量等。
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
内存分区的意义:不同区域存放的数据,赋予不同的生命周期,让变成更加灵活。
之前写的代码都存放在代码区。
程序编译后,生成exe可执行程序,未执行该程序前分为两个区域。(未运行前的两个区)
代码区:
存放CPU执行的机器指令
代码区是共享的(对于频繁被执行的程序,在内存中只保存一份即可)
代码区是只读的(防止程序意外地修改了它的指令)
全局区:
全局变量和静态变量存放在此
全局区包含常量:字符串常量和其它常量
该区域的数据在程序结束后由操作系统释放。
const修饰的局部变量作为常量貌似存在了栈区呢?
#include<iostream>
using namespace std;
//创建全局变量
int g_a = 10;
int g_b = 10;
const int c_g_a = 10;
int main()
{
//创建普通的局部变量
int a = 10;
int b = 10;
cout << "局部变量a的地址为:" << (int)&a << endl;
cout << "局部变量b的地址为:" << (int)&b << endl;
cout << "全局变量g_a的地址为:" << (int)&g_a << endl;
cout << "全局变量g_b的地址为:" << (int)&g_b << endl;
static int s_a = 10;
static int s_b = 10;
cout << "静态变量s_a的地址为:" << (int)&s_a << endl;
cout << "静态变量s_b的地址为:" << (int)&s_b << endl;
//常量分为字符串常量和const修饰的变量,const可以修饰局部变量和全局变量
cout << "字符串常量的地址为:" << (int)&"Hello World" << endl;
//const修饰的局部变量
const int c_s_a = 10;
cout << "const修饰的局部变量的地址为:" << (int)&c_s_a << endl;
//const修饰的全局变量
cout << "const修饰的全局变量的地址为:" << (int)&c_g_a << endl;
system("pause");
return 0;
}
c语言利用malloc函数和free函数申请堆区空间:
1.要自己计算大小 2.要把返回的void*强转为其他类型指针 3.要判断返回值是否为NULL。
需要动态申请内存空间的两个场景:
(1).开辟的连续数组空间大小只有运行后才能确定
//栈:局部变量 函数的参数
//堆: malloc new
//静态常量: static 字符串常量
//int* ptr = malloc(); //指针在栈区,申请的空间在堆区
//malloc calloc realloc _alloca
#include<iostream>
using namespace std;
void main()
{
int n;
cin >> n;
int ar[10] = { 0 };
int* ptr = (int*)malloc(sizeof(int) * n);//动态开辟空间需求1 数组
{
if (NULL == ptr)
{
cout << "Out of Memory" << endl;
return;
}
free(ptr);
ptr = NULL;
}
if (ptr != NULL)
{
*ptr = 10;
}
}
(2)成员变量的指针开辟空间,存放数据。
class Stu
{
public:
Stu(const char* name, int age)
{
//m_name = name;//指针不能直接赋值
this->m_name = (char*)malloc(strlen(name) + 1);//动态内存申请需求1 构造函数
strcpy(m_name, name);
this->m_age = age;
}
private:
char* m_name;
int m_age;
};
void test02()
{
Stu s("abc", 20);
}
int main()
{
test01();
system("pause");
return 0;
}
C语言_alloca函数在栈区动态开辟空间,不能free释放,比较特殊。
//void* _alloca(size_t size);
void test01()
{
int* ptr = (int*)_alloca(sizeof(int) * 10);
//free(ptr);//栈区申请,不用释放
}
c++中的new和delete操作符也是在堆区申请和释放空间的。
1.new delete 开辟或者释放单个对象的空间。new [] 和delete[]申请和释放多个连续的对象空间,相当于搞了一个数组。
2.new操作符不用计算开辟空间大小,不用强转指针,不用判空。
3.malloc free new delete底层实现不一样,不能混用。
4.new 和delete 会调用构造函数,new Test[10]就调用10次,析构也一样。new[]和delete[]必须对应,不然会出现内存泄漏。注意顺序是new开辟空间->调用构造函数->调用析构函数->delete释放空间
5.new对象数组时,类必须有默认构造函数。
6.操作符new和操作符delete即operator new 和operator dalete重载是通过malloc和free实现的,它们的功能仅申请空间,与构造析构无关。
7.打断点可以发现,使用new 和 delete操作符时,会先调用operator new开辟空间,然后调用构造函数进行初始化,接下来调用析构函数销毁数据,最后调用operator delete释放空间。
8.实际在编译器底层也是对new和delete操作符进行了多种重载,执行重载的同时 调用了构造和析构函数。
#include<iostream>
using namespace std;
//c++
//重载new
void* operator new(size_t sz)//无符号类型整形
{
void* ptr = malloc(sz);
return ptr;
}
void operator delete(void* ptr)
{
free(ptr);
}
void* operator new[](size_t sz)//无符号类型整形
{
void* ptr = malloc(sz);
return ptr;
}
void operator delete[](void* ptr)
{
free(ptr);
}
void test00()
{
int* ptr = (int*)malloc(sizeof(int)*10);
if (NULL != ptr)
{
cout << "Out of mamery" << endl;
return;
}
free(ptr);
}
void test01()
{
int* ptr = new int;
*ptr = 10;
delete ptr;
}
void test02()
{
int* ptr = new int[10];
delete[] ptr;
}
void test03()
{
int* ptr1 = (int*)malloc(sizeof(int));
*ptr1 = 10;
free(ptr1);
int* ptr2 = new int(10);
delete ptr2;
}
class Test
{
public:
Test(int d=0)
{
this->m_data;
cout << "Creat Test Obj" <<endl;
}
~Test()
{
cout << "Destory Test Obj" << endl;
}
private:
int m_data;
};
void test04()
{
//Test t;
Test* pt1 = (Test*)malloc(sizeof(Test));//空间申请和空间释放
free(pt1);
Test* pt2 = new Test(10);//1申请空间,2初始化对象(调用构造函数)//new操作符
delete pt2; //1调用析构函数 2释放空间
}
void test05()
{
Test* ptr = new Test[10];//new对象数组时,类必须有默认构造函数
//delete ptr;//malloc 和free不能混用,底层记录的信息和实现细节不对应
delete[] ptr;
}
void test06()
{
Test* ptr = new Test;
delete ptr;
}
void test07()
{
Test* ptr = (Test*)operator new(sizeof(Test));//操作符new,不调用构造析构仅申请释放
operator delete(ptr);
}
int main()
{
test07();
system("pause");
return 0;
}
回调函数来处理申请失败的问题。
void OutOfMemory(void)
{
cout << "OutOfMemory" << endl;
exit(1);
}
void test01()
{
set_new_handler(OutOfMemory);
int* ptr = new int[536870911];
if (ptr == NULL)
{
cout << "aaaaaaaaaaaaa" << endl;
}
cout << "bbbbbbbbbbbbbb" << endl;
}
new和delete也可以在类内重载,类内有优先调用类内的,没有就调全局的,再没有就调底层已经实现的。
class Test
{
public:
void* operator new(size_t sz)//无符号类型整形
{
void* ptr = malloc(sz);
return ptr;
}
void operator delete(void* ptr)
{
free(ptr);
}
void* operator new[](size_t sz)//无符号类型整形
{
void* ptr = malloc(sz);
return ptr;
}
void operator delete[](void* ptr)
{
free(ptr);
}
Test(int d = 0)
{
this->m_data;
cout << "Creat Test Obj" << endl;
}
~Test()
{
cout << "Destory Test Obj" << endl;
}
private:
int m_data;
};
void test02()
{
int* ptr = new int;//调全局
Test* pt = new Test;//调类内
}
针对内置数据类型进行申请时,malloc和new区别不大。
#include<iostream>
using namespace std;
void test01()
{
//申请内置数据类型区别不大
int* ptr = (int*)malloc(sizeof(int));
int* ptr2 = new int;
}
int main()
{
test01();
system("pause");
return 0;
}
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
定位new,在原有空间的指定位置放一个对象,这个对象是在堆上new出来的。基本语法如下:
#include<iostream>
using namespace std;
class Test;
void* operator new(size_t sz, void* ptr, int pos)
{
return &((int*)ptr)[pos];
}
class Test
{
public:
Test(int d = 0)
{
this->m_data=d;
//cout << "Creat Test Obj" << endl;
}
~Test()
{
//cout << "Destory Test Obj" << endl;
}
private:
int m_data;
};
void test01()
{
//int* ptr = (int*)malloc(sizeof(int)*10);
//定位new
int ptr[10];
Test t[10];
//new(ptr,5) int(100);
new (t, 5) Test(200);
}
int main()
{
test01();
system("pause");
return 0;
}