C++复习笔记7

本文详细介绍了C++程序中的内存分区,包括代码区、全局区、栈区和堆区,以及各自的作用和生命周期。同时,讨论了动态内存分配,如new、delete、malloc和free的使用场景和注意事项,强调了内存管理的重要性,包括防止内存泄漏和正确使用new[]与delete[]。此外,还提到了定位new的概念和内存池的关联。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值