C++初阶 —— C/C++内存管理

C++初阶:C/C++内存管理 阅读详情

目录

一,C/C++内存分布

二,内存管理方式 

三,operator new/operator delete函数(重点)

四,new/delete实现原理

五,定位new表达式(placement-new)(了解)

六,附


一,C/C++内存分布

  • 栈(又称堆栈),非静态局部变量、函数参数、返回值等,向下增长;
  • 内存映射段,是高效的I/O映射方式,用于装载一个共享的动态内存库;用户可使用系统接口共享共享内存,做进程通信;
  • 堆,用于程序运行时动态内存分配,向上增长,但不一定有可能使用释放后的低地址;
  • 数据段,存储全局数据和静态数据;
  • 代码段,存储可执行代码和只读常量;

二,内存管理方式 

C语言中动态内存管理方式:malloc、calloc、realloc、free;

C++内存管理方式

new是C++关键字,也是一个运算符,用于对象实例化时,在堆上动态开辟内存,并返回该内存地址;

  • 兼容C语言内存管理方式;
  • 通过new/delete操作符,进行动态内存管理;
  • 动态申请内置类型,与malloc无区别;
  • 动态申请自定义类型,不仅仅会开空间/释放空间,还会调用构造函数和析构函数;

语法:

//单个类型的申请及释放
type* ptr = new type; //开辟空间并调用type类型的构造函数
delete ptr; //调用type类型的析构函数并释放空间
//数组类型的申请及释放
type* ptr = new type[numbers]; //开辟空间并调用numbers个type类型的构造函数
delete[] ptr; //调用numbers个type类型的析构函数并释放空间
//类对象类型的申请及释放,会调用构造函数和析构函数
//可带构造函数参数列表
type* ptr = new MyClass(arg1,arg2,...)
delete ptr;
//new/delete内置类型
int main()
{
	//动态申请一个int类型的空间
	int* ptr1 = new int; 
	//动态申请一个int类型的空间,并赋值10
	int* ptr2 = new int(10);
	//动态申请10个int类型的空间
	int* ptr3 = new int[10];

	delete ptr1;
	delete ptr2;
	delete[] ptr3;
	
	return 0;
}
//new/delete自定义类型
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

int main()
{
	//申请一个A类型的空间
	A* ptr1 = (A*)malloc(sizeof(A));
	free(ptr1);
	//申请10个A类型的空间
	A* ptr2 = (A*)malloc(sizeof(A) * 10);
	free(ptr2);

	//申请一个A类型的空间
	A* ptr3 = new A; //或带初始化值new A(10)
	delete ptr3;
	//申请10个A类型的空间
	A* ptr4 = new A[10];
	delete[] ptr4;
	return 0;
}

三,operator new/operator delete函数(重点)

operator new/operator delete函数

  • new/delete是动态申请和释放的操作符;
  • operator new/operator delete是系统提供的全局函数;
    • new底层:调用operator new全局函数来申请空间 + 构造函数;
    • delete底层:析构函数 + 调用operator delete全局函数来释放空间;
    • operator new实际是通过malloc来申请的;
    • operator delete最终是通过free来释放空间;
//new与malloc区别,new失败会抛异常;
int main()
{
	char* p1 = (char*)malloc((size_t)2 * 1024 * 1024 * 1024);
	//检查p1
	if (p1 == NULL)
		perror("p1");
	
	try
	{
		char* p2 = new char[0x7fffffff]; // 抛异常,捕获异常位置
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

new动态申请时:先调用operator new,在调用构造函数;

delete释放时:先调用析构函数,在调用operator delete;

operator new/operator delete类专属重载(了解)

struct ListNode
{
	ListNode(int data = 0)
		:_next(nullptr)
		,_data(data)
	{}
	ListNode* _next;
	int _data;

	//类专属重载
	//new ListNode申请空间,就会调用此处类专属重载
	void* operator new(size_t n)
	{
		++_count;
		return ::operator new(n); //::是避免自己调用自己,::前为空则为调用全局
	}
	void operator delete(void* p)
	{
		--_count;
		return ::operator delete(p);
	}
	static int _count;
};

int ListNode::_count = 0;

struct ListNode* removeElements(ListNode* head, int val)
{
	ListNode* prev = head;
	ListNode* cur = head;
	while (cur)
	{
		if (cur->_data == val)
		{
			prev->_next = cur->_next;
			delete cur;
			cur = prev->_next;
		}
		else
		{
			prev = cur;
			cur = cur->_next;
		}
	}
	return head;
}

int main()
{
	//创建时先申请空间,在构造函数
	ListNode* node1 = new ListNode(1);
	ListNode* node2 = new ListNode(2);
	ListNode* node3 = new ListNode(3);
	ListNode* node4 = new ListNode(2);
	ListNode* node5 = new ListNode(5);

	node1->_next = node2;
	node2->_next = node3;
	node3->_next = node4;
	node4->_next = node5;

	removeElements(node1, 2);
	cout << ListNode::_count << endl;
	return 0;
}
class Foo
{
public:
	Foo() { cout << "Foo()" << endl; }
	~Foo() { cout << "~Foo()" << endl; }
	static void* operator new(size_t size) throw(std::bad_alloc);
	static void operator delete(void* pMem);
private:
	int _data;
};
//重载operator new
void* Foo::operator new(size_t size) throw(std::bad_alloc)
{
	cout << "allocating " << size << " bytes" << endl;
	void* pMem = malloc(size);
	if (!pMem)throw bad_alloc();
	memset(pMem, 0, size);
	return pMem;
}
//重载operator delete
void Foo::operator delete(void* pMem)
{
	cout << "deallocating memory!" << endl;
	free(pMem);
}

int main()
{
	Foo* p = new Foo;
	delete p;
    return 0;
}

四,new/delete实现原理

内置类型

  • new与malloc,delete与free基本类似;
  • new/delete申请和释放的是单个元素空间;
  • new[]/delete[]申请和释放的是连续空间,且new申请失败会抛异常;

自定义类型

new原理

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

delete原理

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

new Type[N]原理

  • 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请;
  • 在申请的空间上执行N次构造函数;

delete[]原理

  • 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理;
  • 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间;

class Stack
{
public:
	Stack(int capacity = 4)
		:_a(new int[capacity])
		,_size(0)
		,_capacity(capacity)
	{
		cout << "Stack():" << this << endl;
	}
	~Stack()
	{
        delete _a;
        _size = _capacity = 0;
		cout << "~Stack():" << this << endl;
	}
private:
	int* _a;
	int _size;
	int _capacity;
};
//先在栈上main内,开辟Stack大小的空间
//在调用构造函数,在堆上开辟16字节大小空间给_a,在初始化_size/_capacity
//最后main结束时,调用析构函数,销毁堆上开辟16字节空间,_size/_capacity赋零
int main()
{
	Stack st;
	return 0;
}
//先在堆上开辟Stack大小空间给指针p
//在开辟Stack空间时,调用构造函数,再在堆上开辟16字节大小空间给_a,在初始化_size/_capacity
//在delete时,调用析构函数,销毁堆上开辟16字节空间,_size/_capacity赋零,在释放堆上的Stack空间
int main()
{
	Stack* p = new Stack;
	delete p;
	return 0;
}

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A():" << this << endl;
	}
	A(const A& a)
	{
		_a = a._a;
		cout << "A(const A& a)" << this << endl;
	}
	A& operator = (const A& a)
	{
		_a = a._a;
		cout << "A& operator = (const A& a)" << this << endl;
		return *this;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	A a[5]; //调用5次构造
	A* p1 = new A[5]; //调用5次构造
	for (int i = 0; i < 5; i++)
	{
		*(p1 + i) = a[i]; //调用5次赋值重载
	}
	cout << endl;
	return 0;
}
int main()
{
	A a[5];  //调用5次构造
	A* p1 = (A*)malloc(sizeof(A) * 5);
	cout << endl;
	for (int i = 0; i < 5; i++)
	{
        //也称replacement-new
		new(p1 + i) A(a[i]); //调用5次拷贝构造
	}
	cout << endl;
	return 0;
}

五,定位new表达式(placement-new)(了解)

  • 定位new表达式,是在已分配的原始内存空间中调用构造函数初始化一个对象;
  • 实际中一般配合内存池使用,因为内存池分配出的内存没有初始化,所以如是自定义类型对象,需使用new的定义表达式进行显示调构造函数进行初始化;

格式:

  • new(place_address) type 或 new(place_address) type(initializer-list)
  • place_address必须为一个指针,initializer-list是类型的初始化列表;
class A
{
public:
	A(int a = 0, int val = 0)
		:_a(a)
		,_val(val)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
	int _val;
};

int main()
{
	A* p = (A*)malloc(sizeof(A));
	new(p) A(1,2);
	return 0;
}

六,附

malloc/free和new/delete共同点

  • 都是堆上申请空间;
  • 需手动释放;

malloc/free和new/delete不同点

  • malloc/free是函数,new/delete是操作符;
  • malloc申请空间时需传递空间大小,new只需空间类型即可;
  • malloc返回void*需强转,new返回空间类型;
  • malloc申请失败返回NULL使用需判空,new会抛异常;
  • 申请自定义类型时,malloc/free不会调用构造函数/析构函数,new申请空间后会调用构造函数初始化,delete在释放空间前会调用析构函数;

内存泄露

  • 是指因为疏忽或错误导致程序未能释放已经不使用的内存的情况;
  • 并不是内存在物理上的消失,而是失去对该段内存的控制,造成内存的浪费;
  • 长期运行的程序出现内存泄露,如操作系统或后台服务,可能会导致响应越来越慢最终卡死;

内存泄露分类(了解)

  • 堆内存泄露(Heap Leak),是指程序从堆中分配的内存,未被释放;
  • 系统资源泄露,是指程序使用系统分配的资源,如套接字、文件描述、管道等没有使用对应的函数释放掉,导致系统资源浪费;

避免内存泄露

  • 智能指针;
  • 内存泄露检查工具;

注:进程正常结束,都会释放;僵死进程、长期运行的服务器程序、物联网设备等不会释放;

ADC电路项目1——10bit SAR ADC 设计,smic18工艺,有工艺库,有效位数ENOB为9.8 包括详细仿真文档,原理介绍,完整电路图,仿真参数已设好,可直接使用,在自己的电脑上就可以运行仿真。本设计采用 smic18mmrf CMOS 工艺,使用栅压自举电路的采样开关,Vcm-based 开关。电容开关控制电路,10 位 DFF,最后用 10 位理想 DAC 模块将数字码转换为 10 进制量进。时序上级板采样的 DAC 电容阵列,两级动态比较器,比较器异步时钟,SAR 动态逻辑,DAC。10bit SAR ADC 设计,smic18工艺,有工艺库,有效位数ENOB为9.8。 阅读详情

相关推荐

【5G演进】4G到5G演进之网络架构与协议栈

4G到5G演进之网络架构与协议栈

Learning makes me happy (0^◇^0) 5529

C++:函数指针进阶(四):函数对象operator()

C++:函数指针进阶(四):函数对象operator()

C++ JAVA的专栏 3664

相机图像质量研究(22)常见问题总结:CMOS期间对成像的影响--光学串扰

光学串扰是一个比较难以理解的光学现象,实际影响往往不大。一、光学串扰产生的原因通常是入射角度太大,光线在不同通道之间产生了混叠二、光学串扰产生的现象光学串扰容易导致迷宫纹。总结本节讲了光学串扰产生的原因,现象。

xiaoshixiu的专栏 1573

C++特殊类的设计

文章目录设计一个类,只能在堆上创建对象设计一个类,只能在栈上创建对象设计一个类,不能被拷贝设计一个类,不能继承设计一个类,只能创建一个对象(单例模式)单例模式的概念单例模式的实现饿汉模式懒汉模式饿汉模式和懒汉模式的对比懒汉模式的优化单例对象的释放单例对象的直接释放内部垃圾回收类 设计一个类,只能在堆上创建对象 想要的效果实际是没法直接在栈上创建对象。 首先cpp只要创建对象就要调用构造函数,因此先要把构造函数ban掉,把构造函数设计成private。但是单这样自己也创建不了了。 因此提供一个创建的接口,只能

代码笔记本 1203

agent-browser OpenClaw 的最佳搭档

agent-browser 是专为 AI Agent 设计的浏览器自动化工具,目前被公认为 OpenClaw 的最佳配套方案。这份技术文档完整记录了其架构、协议、性能调优与常见问题处理,非常适合想让OpenClaw 真正“上手”互联网的开发者与老用户。

liu_zhiyi的博客 1781

Argoverse轨迹预测实战:从数据加载到地图API应用全解析

本文详细解析了Argoverse数据集在轨迹预测中的应用,从数据加载到地图API的实战技巧全涵盖。通过具体代码示例展示如何高效处理轨迹数据、实现可视化及基础预测模型,帮助开发者快速掌握自动驾驶轨迹预测的核心技术。特别介绍了Argoverse地图API的深度应用和性能优化经验。

weixin_29182481的博客 241

C++学习记录 - operator new、new operator、delete等

文章目录0. placement new0.1 重载placement new1. new operator2. delete operator3. operator new4. operator delete5. new 做了哪些事情?6. array new 与 array delete7. delete[ ] 为什么能够释放数组? 0. placement new 即 原地构造。 用法: int *p = new int(10); // new operator new(p) int(1000);

行仔ovo的博客 446

【AI智能体】Codex 高级进阶使用技巧项目实战操作详解

Codex 高级进阶使用技巧项目实战操作详解

congge 1万+

关于 C++中 while(cin &gt&gt a) 的解释 和 operator void*() 和 bool operator!()的理解

做题的时候,我经常用while(cin>>a)这样的模式来 实现 连续输入 或 统计输入连续数字的个数 等功能,但是一直都对其中的原理感到迷迷糊糊,我觉得只会用怎么行,还得搞明白 其所以然 来。所以看了一些资料和大佬们的博客,然后写这样一篇博客来解释其中的原理。 使用情形 以及 跳出的while(cin>>a)的方法 while(cin>>a)的意思是 只要输入的值有效,那么就执行while体内的语句。while循环结束 (跳出流对象)的时候 ,通过检测其流的..

努力学习的DS 906

5套高颜值AI漫剧女主设定图!直接拿去做漫剧(附完整提示词)

左侧特写放大表现暖棕眼妆、豆沙唇、红宝石首饰、发丝与针织纹理,四个视图严格保持同一人物脸模、发色、服装、首饰和身体比例,柔和复古棚拍光,低饱和酒红与奶油色配色,真实布料、皮革、金属与宝石材质,高级精致角色资产设定图,高清8K。佩戴珍珠与透明水晶耳坠、纤细珍珠项链;左侧特写放大至胸部以上,清晰表现皮肤、眼妆、发丝、耳饰和针织材质,人物四个视图保持同一脸模、发型、服装、饰品和身体比例,柔和棚拍漫射光,轻微地面阴影,高级细腻材质,真实发丝,细腻皮肤,高精度角色资产设定图,高清8K质感。

欢迎来到鸾姝淡月博客,专为程序员和编程爱好者打造的技术博客。我们分享编程语言趋势、开发工具、编程哲学、职业发展等,助你掌握新技术,优化技能,激发编程热情。 1659

数据结构之博弈树搜索(深度优先搜索)

数据结构之博弈树搜索(深度优先搜索)

LucianaiB的博客 1523

C++ operator new、operator delete、operator new []、operator delete []

operator new、operator deleteoperator new、operator delete1、相关调用函数2、new operator 和 operator new3、delete operator 和 operator delete4、new[] 和 delete[]5、运行实例(placement new用法)6、new、delete的不同重载办法实例参考 operator new、operator delete 1、相关调用函数 1、void* operator new(size

JMW1407的博客 1333

2.STM32F407ZGT6 学习笔记-移植 FreeRTOS

1. 在工程下建议FreeRTOS文件夹 2. 在FreeRTOS文件夹下建立 src 和 port 文件夹 (src用于存放freertos源码,port文件夹存放内存和接口相关的文件) 3. 复制freertos/source文件夹下所有c文件复制到刚刚建立的freertos/src目录下 4. 复制FreeRTOSv9.0.0\FreeRTOS\Source\portablex下的MemMang和RVDS文件夹复制到刚刚建立的port问价夹下 5. 将FreeRTOSv9.0.0\FreeRTOS

Car12 1233

C/C++内存管理与初阶模板

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会free一定会释放空间,而析构函数不一定会释放空间new的原理1. 调用operator new函数申请空间2. 在申请的空间上执行构造函数,完成对象的构造delete的原理1. 在空间上执行析构函数,完成对象中资源的清理工作2. 调用operator delete函数释放对象的空间new T[N]的原理。

2502_90291736的博客 827

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

初阶3 C/C++内存管理

对于内置类型来说,malloc和new用法几乎一样,但是对于自定义类型来说,new和delete相比于malloc,会调用构造函数和析构函数这里以链表为列,看看malloc和new的区别malloc:单纯开空间//链表int val;//申请节点int main()// 定义n1节点free(n1);return 0;new:开空间+调用构造函数初始化//链表public://构造函数:_next(nullptr), _val(val) // 初始化列表。

ydm_ymz的博客 1469

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【C++初阶】C/C++内存管理

【C++初阶】C/C++内存管理

2301_78022459的博客 1112

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C++初阶:C/C++内存管理、new与delete详解

1.C/C++内存分布 2.C语言中动态内存管理方式 malloc/calloc/realloc/free 3.C++动态内存管理方式 3.1new/delete操作内置类型 3.2new和delete操作自定义类型 4.operator new与operator delete函数 5.new和delete的实现原理 5.1内置类型 5.2自定义类型 6.定位new表达式(placement-new) 7.知识点梳理 malloc/free和new/delete的区别

qq_74415153的博客 2115

C++初阶-C/C++内存管理

delete p2;return 0;一般不用进行内存检查,其中new互调用自定义类型的构造函数进行初始化,而malloc是不会初始化的。而且delete还会调用自定义类型的析构函数。如果想初始化malloc的可以用for循环初始化,如果没有缺省值,我们可以A* p2=new A(1);

博客是在C++/Java/Liunx/算法的学习阶段所写的博客,内容可能不是很全面 1036

C/C++内存管理&模板初阶

内存管理和模板初阶1 内存管理1.1 C/C++ 的内存分布1.2 C 中动态内存管理方式1.3 C++ 中动态内存管理方式1.3.1 new/delete操作内置类型1.3.2 new/delete操作自定义类型1.3.3 operator new 与 operaror delete 函数1.3.4 new 和 delete 的实现原理1.4 malloc/free 和 new/delete的区别2 模板初阶2.1 泛型编程2.1 函数模板2.1.1 概念2.1.2 格式2.1.3 原理2.1.4 实例化

CZHLNN的博客 1517

<C/C++内存管理>——《C++初阶》

<C/C++内存管理>——《C++初阶》 ——By 作者:新晓·故知

m0_57859086的博客 859

【C++】C/C++内存管理&&模板初阶

C/C++动态内存管理、函数模板和类模板。

大三小白C++进阶之路 1987

【C++初阶】三、C/C++内存管理

C/C++内存分布 | C语言中动态内存管理方式 | C++内存管理方式

枫叶先生的博客 659
上一篇: C++初阶 —— 类与对象(三)
下一篇: C++初阶 —— 模板初阶
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值