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

61-70==c++知识点

知识点目录

          • **61、new和malloc的区别?**
          • **62、delete p、delete [] p、allocator都有什么作用?**
          • 63、new和delete的实现原理, delete是如何知道释放内存的大小的额?
          • 64、malloc申请的存储空间能用delete释放吗
          • 65、malloc与free的实现原理?
          • 66、malloc、realloc、calloc的区别
          • 67、类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表(形参列表)会快一些?
          • 68、成员列表初始化?
          • 69、什么是内存泄露,如何检测与避免
          • 70、对象复用的了解,零拷贝的了解

61、new和malloc的区别?
  • 1、 new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持;
  • 2、 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸
  • 3、** new操作符内存分配成功时,返回的是对象类型的指针**,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。**而malloc内存分配成功则是返回void * **,需要通过强制类型转换将void*指针转换成我们需要的类型。
  • 4、 new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。
  • 5、 new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
62、delete p、delete [] p、allocator都有什么作用?
  • 1、 动态数组管理new一个数组时,[]中必须是一个整数,但是不一定是常量整数,普通数组必须是一个常量整数;
  • 2、 new动态数组返回的并不是数组类型,而是一个元素类型的指针;
  • 3、 delete[]时,数组中的元素按逆序的顺序进行销毁;
  • 4、 **new在内存分配上面有一些局限性,new的机制是将内存分配和对象构造组合在一起,**同样的,delete也是将对象析构和内存释放组合在一起的。allocator将这两部分分开进行,allocator申请一部分内存,不进行初始化对象,只有当需要的时候才进行初始化操作。
63、new和delete的实现原理, delete是如何知道释放内存的大小的额?
  • 1、 new简单类型直接调用operator new分配内存;
    而对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;

    对于简单类型,new[]计算好大小后调用operator new;
    对于复杂数据结构,new[]先调用operator new[]分配内存,然后在p的前四个字节写入数组大小n,然后调用n次构造函数,针对复杂类型,new[]会额外存储数组大小;
    • ① new表达式调用一个名为operator new(operator new[])函数,分配一块足够大的、原始的、未命名的内存空间;
    • ② 编译器运行相应的构造函数以构造这些对象,并为其传入初始值;
    • ③ 对象被分配了空间并构造完成,返回一个指向该对象的指针。
  • 2、delete简单数据类型默认只是调用free函数;复杂数据类型先0调用析构函数再调用operator delete;针对简单类型,delete和delete[]等同。假设指针p指向new[]分配的内存。因为要4字节存储数组大小,实际分配的内存地址为[p-4],系统记录的也是这个地址。delete[]实际释放的就是p-4指向的内存。而delete会直接释放p指向的内存,这个内存根本没有被系统记录,所以会崩溃。
  • 3、需要在 new [ ] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了。
64、malloc申请的存储空间能用delete释放吗
  • 不能,malloc /free主要为了兼容C,new和delete 完全可以取代malloc /free的。
  • malloc /free的操作对象都是必须明确大小的,而且不能用在动态类上。
  • new 和delete会自动进行类型检查和大小,malloc/free不能执行构造函数与析构函数,所以动态对象它是不行的。
  • 当然从理论上说使用malloc申请的内存是可以通过delete释放的。不过一般不这样写的。而且也不能保证每个C++的运行时都能正常。
65、malloc与free的实现原理?
  • 1、 在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk(data段)、mmap(共享)、munmap这些系统调用实现的;
  • 2、 brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中(堆和栈中间(共享),称为文件映射区域的地方)找一块空闲的虚拟内存。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系;
  • 4、 malloc是从堆里面申请内存,也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
66、malloc、realloc、calloc的区别
    1. malloc函数
    void* malloc(unsigned int num_size);
    
    int* p=(int*)malloc(20*sizeof(int));申请20int类型的空间
    
    1. calloc函数
    void* calloc(size_t n,size_t size);
    
    int* p1=calloc(20,sizeof(int));
    
    在这里插入图片描述
    省去了人为空间计算;malloc申请的空间的值是随机的,calloc申请的空间的值是初始化为0;
    1. realloc函数
    void realloc(void* p,size_t new_size);
    
    给动态分配的空间额外的空间,用于扩充容量
67、类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表(形参列表)会快一些?
    1. 赋值初始化,通过在函数体内进行初始化;列表初始化,在冒号后使用初始化列表进行初始化。
      • 这两种方式的区别在于:
    • 对于对于在函数体中初始化,是在所有的数据成员被分配内存空间后才进行的。
    • 列表初始化是给数据成员分配内存空间时就进行初始化,就是说分配一个数据成员只要冒号后有此数据成员的赋值表达式(此表达式必须是括号赋值表达式),那么分配了内存空间后在进入函数体之前给数据成员赋值,就是说初始化这个数据成员此时函数体还未执行。
    1. 一个派生类构造函数的执行顺序如下:
    • ① 虚拟基类的构造函数(多个虚拟基类则按照继承的顺序执行构造函数)。
    • ② 基类的构造函数(多个普通基类也按照继承的顺序执行构造函数)。
    • ③ 类类型的成员对象的构造函数(按照初始化顺序)
    • ④ 派生类自己的构造函数。
    1. 方法一是在构造函数当中做赋值的操作,而方法二是做纯粹的初始化操作。我们都知道,C++的赋值操作是会产生临时对象的。临时对象的出现会降低程序的效率。
68、成员列表初始化?
    1. 必须使用成员初始化的四种情况
    • ① 当初始化一个引用成员时;
    • ② 当初始化一个常量成员时;
    • ③ 当调用一个基类的构造函数,而它拥有一组参数时;
    • ④ 当调用一个成员类的构造函数,而它拥有一组参数时;
    1. 成员初始化列表做了什么\
    • ① 编译器会一一操作初始化列表,以适当的顺序在构造函数之内安插初始化操作,并且在任何显示用户代码之前;
    • ② list中的项目顺序是由类中的成员声明顺序决定的,不是由初始化列表的顺序决定的;
69、什么是内存泄露,如何检测与避免
  • 内存泄露
    • **一般我们常说的内存泄漏是指堆内存的泄漏。**堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定)内存块,使用完后,必须显式释放的内存。。应用程序般使用malloc,、realloc、
      new等函数从堆中分配到块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了(申请用完后,一定要释放,不然就是内存泄漏)
  • 避免内存泄露的几种方式
    • 计数法:使用new或者malloc时,让该数+1,delete或free时,该数-1,程序执行完打印这个计数,如果不为0则表示存在内存泄露
    • 定要将基类的析构函数声明为虚函数(如果基类的析构函数不是虚函数,在我们使用多态的情况下,我们在delete 基类对象并不会释放派生类的资源,只会释放基类的资源)
    • 对象数组的释放一定要用delete []
    • 有new就有delete,有malloc就有free,保证它们一定成对出现
  • 检测工具
    • Linux下可以使用Valgrind工具
    • Windows下可以使用CRT库
70、对象复用的了解,零拷贝的了解
  • 对象复用
    • 对象复用其本质是一种设计模式:Flyweight享元模式。
    • 通过将对象存储到“对象池”中实现对象的重复利用,这样可以避免多次创建重复对象的开销,节约系统资源。
  • 零拷贝
    • 零拷贝就是一种避免 CPU 将数据从一块存储拷贝到另外一块存储的技术。(DMA?)
    • 零拷贝技术可以减少数据拷贝和共享总线操作的次数。
    • 在C++中,vector的一个成员函数emplace_back()很好地体现了零拷贝技术,它跟push_back()函数一样可以将一个元素插入容器尾部,区别在于:使用push_back()函数需要调用拷贝构造函数和转移构造函数,而使用emplace_back()插入的元素原地构造,不需要触发拷贝构造和转移构造,效率更高。
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct Person{
	string name;
	int age;
	//初始构造函数
	Person(String p_name,int p_age):name(p_name),age(p_age)
	{
		cout<<"I have been constructed"<<endl;
	}
	//拷贝构造函数
	//std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
	Person(const Person& other):name(std::move(other.name)),age(other.age)
	{
		cout<<"I have been copy construct"<<endl;
	}
	//转移构造函数
	//右值引用(&&)
	Person(Person&& other):name(std::move(other.name)),age(other.age)
	{
		cout<<"I have been moved"<<endl;
	}
}; 
int main()
{
	 vector<Person> e;
	 cout << "emplace_back:" <<endl;
	 e.emplace_back("Jane", 23); //不用构造类对象
	 
	  vector<Person> p;
	  cout << "push_back:"<<endl;
	  p.push_back(Person("Mike",36));
	  return 0;
}
//输出结果:
//emplace_back:
//I have been constructed

//push_back:
//I have been constructed
//I am being moved.

相关文章:

  • 一文快速上手 Nacos 注册中心+配置中心!
  • 云扩RPA携手中联教育引领财务机器人教学创新
  • 入阿里P6?最少啃完这本阿里最新Java多线程编程手册,建议收藏
  • 【毕业设计】深度学习人脸表情识别系统 - python OpenCV
  • 基于HTML仿华为手机网站电商项目的设计与实现
  • 【Java基础】方法重写、修饰符、权限修饰符及final、static关键字
  • 【C++】之const
  • Stream 的使用,我觉得使用它是非常方便的
  • Tomcat安装及配置教程
  • 图像也是一门语言?微软提出19亿参数的超大通用模型BEIT-3,刷榜多个CV和多模态任务!
  • 如何利用博途PLC PID_Compact 进行PID闭环仿真(一阶对象传递函数)
  • 查题公众号搭建免费教程
  • SpringCloud Sleuth 分布式请求链路追踪
  • 免费搭建搜题公众号教程
  • R 方差分析 analysis of variance
  • 自己简单写的 事件订阅机制
  • [译] 怎样写一个基础的编译器
  • 77. Combinations
  • E-HPC支持多队列管理和自动伸缩
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JS笔记四:作用域、变量(函数)提升
  • Mithril.js 入门介绍
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 开源SQL-on-Hadoop系统一览
  • 两列自适应布局方案整理
  • 嵌入式文件系统
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • # 计算机视觉入门
  • #Linux(帮助手册)
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (3)nginx 配置(nginx.conf)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (C++)八皇后问题
  • (done) 两个矩阵 “相似” 是什么意思?
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (五)c52学习之旅-静态数码管
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)h264中avc和flv数据的解析
  • (转)创业家杂志:UCWEB天使第一步
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .Net 8.0 新的变化
  • .net Application的目录
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET 服务 ServiceController
  • .Net 知识杂记
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @Autowired多个相同类型bean装配问题
  • @requestBody写与不写的情况
  • [ 转载 ] SharePoint 资料