C++ 动态内存 new/delete用法

Posted Jqivin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 动态内存 new/delete用法相关的知识,希望对你有一定的参考价值。


一、动态内存是什么?

动态内存是在堆区空间的内存。是指在程序运行过程中动态分配的内存。这些内存如果程序员不自己释放,操作系统不会帮你释放。通过new申请,delete释放。
栈内存:保存定义在函数内部的的非静态对象(或变量),函数作用域结束函数栈帧销毁,这个函数所使用的栈内存就被释放,由操作系统管理。
静态内存:使用之前分配,程序结束销毁。

二、何时使用动态内存

1.程序不知道自己使用多少对象
2.程序不知道所需对象的准确类型
3.程序需要在多个对象间共享数据
就比如容器类。

一个小例子

using namespace std;

class Object
{private:int a;
public:
	Object(int n = 0) :a(n) { cout << "construct" << endl; }
	~Object() { cout << "destory" << endl; }
	int get() {	return a;}
};

Object* fun1()
{
	Object o1(10);
	Object* p1 = &o1;
	return p1;
}
Object* fun2()
{
	Object* p2 = new Object(20);
	return p2;
}
int main()
{
	Object* p1 = fun1();
	cout << p1->get() << endl;
	Object* p2 = fun2();
	cout << p2->get() << endl;
	delete p2;
	return 0;	
}

输出结果:栈区资源函数结束就被释放掉了,堆区空间并没有被释放掉。
在这里插入图片描述

三、new/delete的使用

1.new开辟动态内存

new有三种用法
(1)关键字new :申请空间,构建对象
(2)::operator new:只是申请空间,不构建对象
(3)定位new:在一块已经分配成功的内存上重新构造对象
一般(2)(3)一块使用

#include<iostream>
#include<memory>
using namespace std;
#if 1
class Object
{
private:
	int value;
public:
	Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
	~Object() { cout << "destruct Object" << endl; }
	int Value() { return value; }
	const int  Value() const { return value; }
};
int main()
{
	//new的用法 (1)关键字
	int* i = new int(10);
	Object* obj = new Object(10);  delete obj;
	int* is = new int[] {1, 2, 3};    //new []
	delete is;
	unique_ptr<int[]> ps1(new int[10]{ 1,2,3,4,5,6,7,8,9,10 });   //和智能指针一块使用

	Object* Obj = new Object[]{ 10,20,30 };           //只能用Object*接收,可以使用[]
	cout << Obj[1].Value() << endl;
	delete []Obj;
	unique_ptr<Object[] > pobj(new Object[]{ 10,20,30 });

	//(2)operator new     --- 类似malloc
	int* io = (int*)::operator new(sizeof(int));  cout << *io << endl;//还未赋值,所以是随机值
	int* ios = (int*)::operator new(sizeof(int)*3);
	Object* objo = (Object*)::operator new(sizeof(Object));
	//Object* obja = (Object*)::operator new(sizeof(Object) * 3);  //数组空间
	void* obja = operator new(sizeof(Object) * 3);

	//(3)定位new
	new(io) int(100);
	new(ios) int[3]{ 1,2,3 };
	objo = new(objo) Object(1);
	Object* objas = new(obja) Object[3]{ 11,22,33 };

	for (int i = 0; i < 3; i++)
	{
		cout << ios[i] << " " << objas[i].Value() << endl;
	}
	delete io; delete ios; //不用[]
	delete objo; 
	//delete [] 不可以使用
	for (int i = 0; i < 3; i++)
	{
		objas[i].~Object();
	}
	delete objas;
	return 0;
}
#endif

结果

2. delete释放内存

delete有两个动作:
(1)调用对象的析构,销毁对象
(2)释放对象占用的堆区空间。
在这里插入图片描述
delete 指针变量名; //必须是指针变量名,不能是对象。
delete [] 释放数组对象。

四、关于new的用法区别

new [] 创建数组对象的时候,会在头部信息中保存数组中有几个元素,所以可以使用
delete[],    
operator new相当于malloc,数据区域上方保存的是越界标志,如果这个时候
使用delete[]    会把越界标志当做元素个数,所以会出现调用0xfdfdfdfd次析构函数。

代码

class Object
{
private:
	int value;
public:
	Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
	~Object() { cout << "destruct Object" << endl; }
	int Value() { return value; }
	const int  Value() const { return value; }
};
int main()
{
	Object* p = (Object*)::operator new(sizeof(Object) * 3);
	new(p) Object[3]{ Object(10),Object(20),Object(30) };
	Object* p1 = new Object[3]{ Object(10),Object(20),Object(30) };

	for (int i = 0; i < 3; i++)
	{
		cout << p[i].Value() << endl;
	}
	for (int i = 0; i < 3; i++)
	{
		cout << p1[i].Value() << endl;
	}
	delete[] p1;
	delete []p;  
}

结果会调用0xfdfdfdfd次析构函数。
在这里插入图片描述
正确的写法:

    delete[] p1;
	for (int i = 0; i < 3; i++)
	{
		p[i].~Object();
	}
	delete p;

在这里插入图片描述
原因: new[] 会记录数组中元素的个数,delete[]的时候会知道调用几次析构函数,但是operator new相当于malloc只有上越界标志,没有元素个数,所以执行delete[]的时候会错把上越界标志当成元素个数,从而一直执行析构函数。
在这里插入图片描述

总结:

operator new + 定位new构造数组对象时,不要使用delete[].

以上是关于C++ 动态内存 new/delete用法的主要内容,如果未能解决你的问题,请参考以下文章

C++动态内存管理

C++动态内存管理

C++动态内存管理

c++基础_ new, delete概述及其使用!!

C++动态内存常见面试题解析

浅谈new/delete和malloc/free的用法与区别