c++——内存

new和delete

c++中静态变量和全局变量存放的区域叫做数据段(c语言叫做静态区),而常量存放的区域叫做代码段(c语言叫做常量区)。

int globalVar = 1;//数据段
static int staticGlobalVar = 1;//数据段
void Test()
{
 static int staticVar = 1;//数据段
 int localVar = 1;//栈
 int num1[10] = { 1, 2, 3, 4 };//栈
 char char2[] = "abcd";//char2是一个数组,存在于栈区。等号右边虽然给的是一个常量字符串,但是等号右边说明在栈上开了一个数组,然后把常量字符串拷贝了过来,数组大小是5个字节,存放包括'\0'。数组名是首元素的地址,*char2就是数组首元素,也是在栈上面。strlen(char2)=4。
 const char* pChar3 = "abcd";//pchar3也是一个局部变量。存在栈上面。但是*pchar3是在代码段。strlen(pchar3)=4。
 int* ptr1 = (int*)malloc(sizeof(int) * 4);//ptr1是一个指针,是一个局部变量,局部变量都是随着栈帧走的,在栈上面。但是*ptr1是在堆上面。
 free(ptr1);
//char2和pchar3指向的内容虽然是一样的,但是char2的内容是可以更改的,但是pchar3这个局部变量存放的栈区,但是他说指向的内容是在数据段。
//全局变量、全局静态变量、局部静态变量虽然生命周期一样,但是作用域是不同的。
}

new和malloc对于内置类型默认是不会初始化的,但是new有办法可以对内置类型进行初始化

int main()
{
	//int* p1 = new int;  // 不会初始化
	int* p1 = new int(10); // 申请一个int,初始化10
	int* p3 = new int[10]; // 申请10个int的数组,但不会初始化
	int* p4 = new int[10] {1, 2, 3, 4};//申请10个int大小的整型数组,并且初始化成1、2、3、4
	return 0;
}

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是 系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。

new的原理 :调用operator new函数申请空间 ;在申请的空间上执行构造函数,完成对象的构造

delete的原理 :在空间上执行析构函数,完成对象中资源的清理工作 ;调用operator delete函数释放对象的空间 

int main()
{
	//new失败了抛异常
	int* p1 = (int*)operator new(sizeof(int*));

	//malloc失败返回nullptr
	int* p2 = (int*)malloc(sizeof(int*));
	if (p2 == nullptr)
	{
		perror("malloc fail");
	}
	// 申请空间 operator new -> 封装malloc(operator new就相当于c语言中的malloc)
	// 调用构造函数
	A* p5 = new A;

	// 先调用析构函数
	// 再operator delete -> 封装free p5指向的空间(operator delete就相当于c语言中的free)
	// operator delete -> free
	delete p5;
	// 申请空间 operator new[] ->operator new-> 封装malloc
	// 调用10次构造函数
	A* p6 = new A[10];
	
	// 先调用10次析构函数
	// 再operator delete[] p6指向的空间
	delete[] p6;
	int* p7 = new int[10];//p7、p8这些局部变量是在栈上的,但是所指向的空间是在对堆上面的。堆上的东西要手动释放,栈上的东西出了栈会自动销毁。
	free(p7);  // 正常释放,不会发生内存泄漏,因为是内置类型,没有构造函数和析构函数的说法。如果此处采用delete,因为没有析构函数,所以delete也是去调用operator delete,operator delete也是去调用free。和直接free区别不大,只是delete前后多了检查的问题,但这不会影响程序的正常运行
	A* p8 = new A;
	free(p8); //不会报错,但是没调用的析构函数,如果析构函数没有资源清理,此时不调用析构函数其实并没有什么问题。但是析构函数存在资源清理或者释放,不调用析构就会存在内存泄漏。
    A a;//自定义类型,回去调用构造函数,出了作用域回去调用析构 
    A* pa;//但这是指针,属于内置类型,不会去调用构造函数
    A* pa = new A;//但是这样写是会去调用构造函数的,但是pa出了作用域光靠该行代码是不回去调用析构函数的
    delete pa;//该行代码必须写,写了就会去调用析构函数,不写是不会去调用析构函数的
}

 结论:new/malloc系列,有底层实现机制也有关联交叉。不匹配使用可能有问题,也可能没有问题,建议一定要匹配使用。

Stack st:st存在于栈区,会主动调用构造函数,其三个成员变量也全部存在于栈区
Stack* ps = new Stack;new的底层原理首先会在堆区申请空间stack,然后再调用构造函数未stack的成员变量_a再堆区申请空间,delete pst就会先调用析构函数释放_a指向的空间,然后在调用operator delete释放pst指向的栈空间。如果free pst会导致只释放了pst指向的stack的空间,而没有释放_a指向的空间,造成内存泄漏。


 

 定位new表达式

int main()
{
	A aa;

	A* p1 = (A*)malloc(sizeof(A));//现在对于P1对象已经没有办法初始化了,因为成员是私有的,而且构造函数有没有办法显示调用,构造函数是在定义对象的时候自动调用的比如说上面的A aa。
	if (p1 == nullptr)
	{
		perror("malloc fail");
	}
//c++如何对一块已有的空间进行初始化————定位new
    new(p1)A(1);//这样就对一个已有的未初始化空间p1调用构造函数,并且参数设为1堆该空间进行初始化
    p1->~A();//析构函数是可以显示调用的,平常我们是采用的free(p1)
}
//使用定位new的情况:以前我们申请内存都是像堆去进行申请的,但是效率太低。现在先让内存池像堆去申请大量的内存,储备好足够的内存。然后以后直接向内存池去申请内存,内存池的内存是没有初始化的,这时候后定位new的作用就显现出来了。内存池的好处是大大的提高效率,减少了申请内存的交互。但是会存在浪费。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值