爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

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

      首页 知识中心 软件开发 文章详情页

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

      2024-05-28 08:15:10 阅读次数:42

      c++,c语言

       

      一、 C/C++内存管理

      1. C/C++内存分布

      我们先来看下面的一段代码和相关问题:

      int main()
      {
      	int globalVar = 1;
      	static int staticGlobalVar = 1;
      	static int staticVar = 1;
      	int localVar = 1;
      	int num1[10] = { 1, 2, 3, 4 };
      	char char2[] = "abcd";
      	const char* pChar3 = "abcd";
      	int* ptr1 = (int*)malloc(sizeof(int) * 4);
      	int* ptr2 = (int*)calloc(4, sizeof(int));
      	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
      	free(ptr1);
      	free(ptr3);
      	return 0;
      }
      

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

      💕 这里我们来说明一下:

      1. 栈 又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
      2. 内存映射段 是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
      3. 堆 用于程序运行时动态内存分配,堆是可以上增长的。
      4. 数据段 --存储全局数据和静态数据。
      5. 代码段 --可执行的代码/只读常量

      【面试题】

      malloc/calloc/realloc的区别?

      • malloc 用于开辟一块动态内存,使用时需要指定开辟的空间大小 (字节),如果开辟成功返回空间的起始地址,如果开辟失败返回 NULL,且不会初始化;
      • calloc 的用法和 malloc 类似,只是它有两个参数,第一个参数为元素个数,第二个参数为每个元素的大小,并且它会将该空间中的数据全部初始化为0;
      • realloc 用于空间的扩容/缩容,它有两个参数,第一个参数为需要调整的动态内存的起始地址,第二个参数为调整后的空间大小,如果第一个参数为 NULL,则它等价于 malloc;如果扩容,编译器会检查原空间后是否有足够的空间,如果足够,就直接扩容并返回原空间的起始地址,如果不够,就新开辟一块空间,然后将原空间的数据拷贝到新空间并返回新空间的地址,最后再释放原空间;如果缩容,编译器会直接新开辟一块空间,然后拷贝原空间数据到新空间并返回新空间的地址,再释放原空间。

      2. C++内存管理方式

      C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

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

      这里我们需要知道:new和delete是操作符/关键字,所以它们的后面不用加(),只需要直接跟类型即可,当然,new操作符是可以在开辟空间的时候直接初始化的。

      💕 new/delete操作内置类型

      int main()
      {
      	int* p = 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};//在开辟空间时直接初始化
      
      	int* p2 = (int*)malloc(sizeof(int));
      	if (p2 == nullptr)
      	{
      		perror("malloc fail");
      	}
      	delete p;
      	delete p1;
      	delete[] p3;
      	delete[] p4;
      	free(p2);
      	return 0;
      }
      

      注意: 申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

      💕 new/delete操作自定义类型

      但是,我们有没有想过这样一个问题,难道new和delete发明出来就是因为比malloc那些C语言的函数写起来更方便吗?很显然并不是这样的。

      这是因为:C语言 malloc/calloc/realloc 函数只负责开辟空间,free 函数只负责销毁空间;而C++在申请自定义类型的空间时,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* p = (A*)malloc(sizeof(A));
      	
      	free(p);
      
      	A* pp = new A;
      	delete pp;
      
      	return 0;
      }
      

      【C++】C/C++内存管理&&模板初阶
      这里我们看到只有使用new和delete操作符时才会调用自定义类型的构造函数和析构函数。而malloc与free不会。


      3. operator new与operator delete函数

      new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过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)
      

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

      operator new 实际是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。


      4. new和delete的实现原理

      💕 内置类型

      如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

      💕 自定义类型

      new的原理

      1. 调用operator new函数申请空间
      2. 在申请的空间上执行构造函数,完成对象的构造

      delete的原理

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

      new T[N]的原理

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

      delete[]的原理

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

      5. 定位new表达式

      定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

      💕 使用格式

      new (place_address) type或者new (place_address) type(initializer-list)

      place_address必须是一个指针,initializer-list是类型的初始化列表

      💕 使用场景

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

      class A
      {
      public:
      	A(int a = 0)
      		: _a(a)
      	{
      		cout << "A():" << this << endl;
      	}
      
      	~A()
      	{
      		cout << "~A():" << this << endl;
      	}
      private:
      	int _a;
      };
      int main()
      {
      	// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
      	A* p1 = (A*)malloc(sizeof(A));
      	new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参
      	p1->~A();
      	free(p1);
      
      	A* p2 = (A*)operator new(sizeof(A));
      	new(p2)A(10);
      	p2->~A();
      	operator delete(p2);
      	return 0;
      }
      

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


      6. 常见面试题

      malloc/free和new/delete的区别

      malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地
      方是:

      1. malloc和free是函数,new和delete是操作符。
      2. malloc申请的空间不会初始化,new可以初始化。
      3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可。
      4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型。
      5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
      6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

      内存泄漏

      💕 什么是内存泄漏,内存泄漏的危害

      什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内
      存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对
      该段内存的控制,因而造成了内存的浪费。

      内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现
      内存泄漏会导致响应越来越慢,最终卡死。

      💕 内存泄漏分类(了解)

      C/C++程序中一般我们关心两种方面的内存泄漏:

      • 堆内存泄漏(Heap leak)
        堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

      • 系统资源泄漏
        指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

      💕 如何检测内存泄漏(了解)

      int main()
      {
      	int* p = new int[10];
      	// 将该函数放在main函数之后,每次程序退出的时候就会检测是否存在内存泄漏
      	_CrtDumpMemoryLeaks();
      	return 0;
      }
      

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

      程序退出后,在输出窗口中可以检测到泄漏了多少字节,但是没有具体的位置。

      因此写代码时一定要小心,尤其是动态内存操作时,一定要记着释放。但有些情况下总是防不胜防,简单的可以采用上述方式快速定位下。如果工程比较大,内存泄漏位置比较多,不太好查时一般都是借助第三方内存泄漏检测工具处理的。

      • 在Linux下内存泄露检测:【Linux下几款内存泄漏检测工具】
      • 在windows下使用第三方工具:【VLD工具说明】
      • 其他工具:【内存泄漏工具比较】

      💕 如何避免内存泄漏

      1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
      2. 采用RAII思想或者智能指针来管理资源。
      3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
      4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

      总结一下:

      内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄
      漏检测工具。


      二、模板初阶

      1. 泛型编程

      如何实现一个通用的交换函数呢?

      void Swap(int& left, int& right)
      {
      	int tmp = left;
      	left = right;
      	right = tmp;
      }
      
      void Swap(char& left, char& right)
      {
      	char tmp = left;
      	left = right;
      	right = tmp;
      }
      
      void Swap(double& left, double& right)
      {
      	double temp = left;
      	left = right;
      	right = temp;
      }
      

      使用函数重载虽然可以实现,但是有以下几个不好的地方:

      1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。
      2. 代码的可维护性比较低,一个出错可能所有的重载均出错。

      那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

      如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。

      泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

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


      2. 函数模板

      💕 函数模板的概念

      函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

      💕 函数模板的格式

      template<typename 类型参数1, typename 类型参数2,......,typename 类型参数n>

      返回值类型 函数名(参数列表){}

      template<typename T>
      void Swap( T& left, T& right)
      {
      	T temp = left;
      	left = right;
      	right = temp;
      }
      

      注意: typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

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

      这里我们可以看到,有了函数模板之后,这里就会很方便了。我们就可以使用不同类型的参数来调用同一函数了。

      💕 函数模板的原理

      函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器

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

      在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。 比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码, 对于字符类型也是如此。

      💕 函数模板的实例化

      用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

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

      这里编译器会根据实参类型自动去推演模板参数的类型,然后去实例化出对应的函数。

      template<class T>
      T Add(const T& left, const T& right)
      {
      	return left + right;
      }
      
      int main()
      {
      	int a1 = 10, a2 = 20;
      	double d1 = 10.0, d2 = 20.0;
      	Add(a1, d1);
      
      	return 0;
      }
      

      该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型。通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错。

      注意: 在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅。

      这个时候我们有两种方法来解决上述问题:

      int main()
      {
      	int a1 = 10, a2 = 20;
      	double d1 = 10.0, d2 = 20.0;
      	//1. 用户自己来强制转化 
      	Add(a1, (int)d1);
      	//2. 使用显式实例化—— 在函数名后的<>中指定模板参数的实际类型
      	Add<int>(a1, d1);
      	return 0;
      }
      

      如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

      💕 模板参数的匹配原则

      (1) 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

      // 专门处理int的加法函数
      int Add(int left, int right)
      {
      	return left + right;
      }
      // 通用加法函数
      template<class T>
      T Add(T left, T right)
      {
      	return left + right;
      }
      
      int main(){
      	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
      	Add<int>(1, 2); // 调用编译器特化的Add版本
      	return 0;
      }
      

      如果一个非模板参数和一个同名的函数模板同时存在,如果我们不显示实例化,编译器会去调用非模板参数,如果我们显示实例化,编译器则会调用函数模板实例化得到的函数。

      (2) 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。

      // 专门处理int的加法函数
      int Add(int left, int right)
      {
      	return left + right;
      }
      // 通用加法函数
      template<class T>
      T Add(T left, T right)
      {
      	return left + right;
      }
      
      int main(){
      	Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
      	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
      	return 0;
      }
      

      (3) 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。


      3. 类模板

      在我们以前的类中,一个类只能实例一种类型的对象,为了和函数模板一样,所以我们引入了类模板。

      💕 类模板的定义格式:

      template<class T1, class T2, ..., class Tn>
      class 类模板名
      {
      // 类内成员定义
      };
      

      下面我们可以使用类模板修改一下Stack这个类:

      template<class T>
      class Stack
      {
      public:
      	Stack(int capaicty = 4)
      	{
      		_a = new T[capaicty];
      		_top = 0;
      		_capacity = capaicty;
      	}
      
      	~Stack()
      	{
      		delete[] _a;
      		_capacity = _top = 0;
      	}
      
      private:
      	T* _a;
      	size_t _top;
      	size_t _capacity;
      };
      

      💕 类模板的实例化

      类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

      int main()
      {
      	//Stack类名,Stack<int>才是类型
      	Stack<int>st1;
      	Stack<double>st2;
      	return 0;
      }
      

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://chenjiale.blog.csdn.net/article/details/128997792,作者:星河万里᭄ꦿ࿐,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:第一季:14redis持久化【Java面试题】

      下一篇:给定一棵树的头节点head,原本是一棵正常的树, 现在,在树上多加了一条冗余的边, 请找到这条冗余的边并返回。

      相关文章

      2025-05-19 09:04:53

      查看RISC-V版本的gcc中默认定义的宏

      查看RISC-V版本的gcc中默认定义的宏

      2025-05-19 09:04:53
      c++ , linux
      2025-04-14 09:26:51

      STL详解(八)—— stack和queue的模拟实现

      stack和queue有一点需要注意的是,虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque容器。

      2025-04-14 09:26:51
      c++ , queue , stack , stl
      2025-04-14 09:26:51

      【算法入门08】青蛙跳台阶

      【算法入门08】青蛙跳台阶

      2025-04-14 09:26:51
      c++ , 动态规划 , 算法
      2025-04-14 09:26:51

      STL详解(九)—— priority_queue的使用与模拟实现

      优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。

      2025-04-14 09:26:51
      c++ , stl , 数据结构
      2025-04-14 09:24:23

      【算法入门14】二叉树的镜像

      【算法入门14】二叉树的镜像

      2025-04-14 09:24:23
      c++ , 算法
      2025-04-14 09:24:23

      【算法入门09】矩形覆盖

      【算法入门09】矩形覆盖

      2025-04-14 09:24:23
      c++ , 动态规划 , 算法
      2025-04-01 10:29:12

      golang与 C++数据结构类型对应关系是怎样的?

      uintptr和unsafe.Pointer相当于c++的void*,也就是任意指针。

      2025-04-01 10:29:12
      c++ , golang , 函数指针 , 数据结构
      2025-04-01 09:21:49

      【C语言】探索数据的存储(上篇)

      【C语言】探索数据的存储(上篇)

      2025-04-01 09:21:49
      c语言 , 后端 , 开发语言
      2025-03-31 08:49:58

      算法题:剑指 Offer 40. 最小的k个数(题目+思路+代码+注释)时空 O(N*LogN) O(1) 0ms击败56%、32%用户

      算法题:剑指 Offer 40. 最小的k个数(题目+思路+代码+注释)时空 O(N*LogN) O(1) 0ms击败56%、32%用户

      2025-03-31 08:49:58
      c语言 , leetcode , 算法
      2025-03-31 08:49:25

      MFC编程 -- 判断是否按下ctrl和shift键

      MFC编程 -- 判断是否按下ctrl和shift键

      2025-03-31 08:49:25
      c++ , mfc , 开发语言
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5220602

      查看更多

      最新文章

      golang与 C++数据结构类型对应关系是怎样的?

      2025-04-01 10:29:12

      【C语言】探索数据的存储(上篇)

      2025-04-01 09:21:49

      算法题:剑指 Offer 40. 最小的k个数(题目+思路+代码+注释)时空 O(N*LogN) O(1) 0ms击败56%、32%用户

      2025-03-31 08:49:58

      MFC编程 -- 判断是否按下ctrl和shift键

      2025-03-31 08:49:25

      MFC编程 -- 读取文件内容

      2025-03-31 08:48:59

      MFC编程 -- 浮点数与字符串之间转换

      2025-03-31 08:48:59

      查看更多

      热门文章

      Lambda函数

      2023-02-08 10:33:56

      QT中多线程的使用

      2023-02-07 10:34:04

      0030 简单的四则运算 c/c++

      2023-03-21 10:39:47

      C++虚函数知识点总结

      2023-02-21 06:21:46

      C语言结构体与结构体指针的使用

      2023-03-08 10:38:36

      指针(*)、取地址(&)、解引用(*)与引用(&)

      2023-04-10 08:54:19

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      C++复制构造函数和移动构造函数的性能速度对比

      新手C语言学习(3)

      Ubuntu VSCode 配置C++环境

      C语言------函数

      C语言函数中链式访问的一个有趣的题目

      C语言零碎知识点之定义指针时星号靠近类型名还是变量名

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号