当前位置: 首页 > news >正文

【c++】c++内存管理

目录

  • c和c++的内存分布
  • 回顾C语言动态管理内存的方式
    • malloc
    • calloc
    • realloc
    • free
  • C++动态管理内存的方式
    • new和delete
    • operator new和operator delete
    • 定位new

c和c++的内存分布

在这里插入图片描述

回顾C语言动态管理内存的方式

malloc

void* malloc (size_t size);

malloc可以在堆上开辟指定内存的空间,参数是要开辟的空间的大小(单位字节),返回开辟好的空间的指针,注意返回的是无类型指针,需要强转一下指针类型,malloc也不会对开辟好的空间进行初始化。

calloc

void* calloc (size_t num, size_t size);

calloc同样是在堆上开辟指定内存的空间,但它要穿两个参数,num是要开辟的单元数,size是一个单元数的尺寸(单位字节),开辟的总空间大小就是num*size。calloc会对开辟的内存进行初始化,calloc同样返回无类型指针,需要强转。realloc的效率略低于malloc。

realloc

void* realloc (void* ptr, size_t size);

realloc可以更改开辟好的空间的大小,ptr给定需要改变的空间的地址,size为更改后的大小。realloc的扩容分为两种情况,原地扩和异地扩,因为开辟的空间要求是连续的,而堆上操作系统管理的内存并不一定就是连续的,当需要调整的空间后面有连续的空间且容纳的下扩容后的空间就直接原地扩容,以上条件不能满足时系统就会在另一边地方开辟size大小的空间,再把ptr上的数据拷贝过来完成拷贝。显然,原地扩的效率大于异地扩。当ptr为空指针时,realloc效果类似于malloc,当size为0时,realloc效果类似于free,但不推荐因此将realloc当malloc和free使用。calloc同样返回无类型指针,需要强转。

free


void free (void* ptr);

free可以释放动态开辟的内存,动态开辟内存后务必释放,不然会内存泄漏,一片空间只能释放一次。

C++动态管理内存的方式

new和delete

new和delete是c++中的关键字,new可以在堆上动态开辟内存并构造对象。delete可以释放new开辟的空间。使用方法如下。

int main()
{
	int* a = new int;//开空间不初始化
	int* b = new int(1);//开空间初始化
	int* c = new int[10];//开10个int类型的空间不初始化
	int* d = new int[10] {};//开10个int类型的空间初始化为0
	int* e = new int[10] {0};//开10个int类型的空间初始化为0
	int* f = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//开10个int类型的空间初始化为想要的数
	string* g = new string;//开类类型空间不初始化(调用默认构造)
	string* h = new string("Hello World");//开类类型空间初始化(调用构造)
	string* i = new string[10];//开10个类类型数组不初始化(调用10次默认构造)
	string* j = new string[10]{"jiunian"};//开10个类类型数组初始化了第一个(第一个调用构造,其他默认构造)
	delete a;
	delete b;//不是数组直接删
	delete[] c;
	delete[] d;
	delete[] e;
	delete[] f;//是数组delete后面加[]再删,注意此时delete[]为一个整体,delete[]本身为一个操作符。
	delete g;
	delete h;//类类型删除会调用析构函数
	delete[] i;
	delete[] j;//调用10次析构函数
	return 0;
}

new和delete与malloc、calloc、realloc、free的区别是:
1.new和delete是操作符,而malloc、calloc、realloc、free是函数。
2.new和delete在创建类类型对象以及销毁时会调用构造和析构函数。
3.new和delete不需要计算类型大小,也不用强转指针类型,malloc、calloc、realloc、free需要。

operator new和operator delete

/*
 operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空
间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK);  /* block other threads */
	__TRY
		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK);  /* release other threads */
	__END_TRY_FINALLY
	return;
}
/*
free的实现
*/
#define   free(p) _free_dbg(p, _NORMAL_BLOCK)

operator new和operator delete是系统提供的全局函数,用来开辟内存空间。操作符new的底层就是通过operator new来申请空间的,操作符delete的底层就是通过operator delete来释放空间的。需要注意的是,operator new和operator delete仍然是通过malloc和free来进行内存的开辟与释放的。另外,需要注意new的作用不只是开辟空间,它还会对空间进行初始化,而delete也不只是释放空间,它还会清空数据。这点在类类型对象的内存开辟时就显得尤为明显,new会调用构造函数,delete会调用析构函数,所以不能简单地将new与operator new、delete与operator delete划等号,他们完全不是一个东西。new与delete是操作符,用法固定;operator new、operator delete是运算符重载函数,可以被重载,自定义成想要的空间开辟方式,如果在全局域或局部域中重载operator new和operator delete(注意重载了operator new就一定要重载对应的operator delete),原来的operator new和operator delete会被覆盖·,此时在这个域中使用new和delete会以自己定义好的方式开辟内存,但在局部域中重载operator new和operator delete可以通过::new、::delete的方式使用原来的operator new和operator delete,所以重载operator new和operator delete的操作建议在局部域中完成,冒然在全局域中重载覆盖原来的operator new和operator delete会然之前写的正常版本的new和delete失效。

定位new

new (address) Type(arguments);

定位new可以在开辟好的内存空间上调用构造函数初始化一个对象,定位new不再会先分配空间再初始化,因为是使用已分配的空间,所以定位new是直接调用构造函数。定位new常被用于内存池管理等方面。具体使用方法如下。

int main()
{
	std::string* buffer = (std::string*)malloc(sizeof(std::string) * 10);//开辟10个string的空间
	std::string* obj = new(buffer)std::string("Hello World");//取开头的一个初始化
	return 0;
}

相关文章:

  • LeetCode 1287.有序数组中出现次数超过25%的元素:遍历
  • 20250214 随笔 Nginx 负载均衡在数据库中的应用
  • 车辆路径问题(VRP)分支定价算法中的分支策略
  • 【C++ 算法竞赛函数速查表】
  • Leetcode 3458. Select K Disjoint Special Substrings
  • 算法学习036 C++最长上升子序列LIS 动态规划DP算法实现最长上升子序列 中小学算法思维学习 比赛算法题解 信奥算法解析
  • Wireshark 输出 数据包列表本身的值
  • SpringBoot中集成SaToken
  • vue3开发打年兽功能
  • 【论文笔记】On Generative Agents in Recommendation
  • DeepSeek 本地部署方法介绍
  • 鸡兔同笼问题
  • 20.【线性代数】——坐标系中,平行四边形面积=矩阵的行列式
  • ES快照备份索引数据(已亲测)
  • 数据恢复-01-机械硬盘的物理与逻辑结构
  • 【C语言】第二期——运算符与表达式
  • PMBOK第7版整体架构全面详解
  • AI芯片:科技变革的核心驱动力
  • QT (四)模型/视图 QFileSystemModel,QStringListModel,QStandardItemModel
  • 【生产变更】- 集群中配置SCAN ip的不同端口应用
  • 九江宜春领导干部任前公示,3人拟提名为县(市、区)长候选人
  • 秘鲁总统任命前司法部长阿拉纳为新总理
  • 盛和资源海外找稀土矿提速:拟超7亿元收购匹克,加快推动坦桑尼亚项目
  • 知名猎头公司创始人兼首席执行官庄华因突发疾病逝世,享年62岁
  • 以军向也门3个港口的居民发布撤离令
  • “大鼻子情圣”德帕迪约因性侵被判缓刑,还有新的官司等着他