[C++面试] new、delete相关面试点
一、入门
1、说说new与malloc的基本用途
int* p1 = (int*)malloc(sizeof(int)); // C风格
int* p2 = new int(10); // C++风格,初始化为10
new 是 C++ 中的运算符,用于在堆上动态分配内存并调用对象的构造函数,会自动计算所需内存大小。
#include <iostream>
int main() {int* ptr = new int(5);std::cout << *ptr << std::endl;delete ptr;return 0;
}
malloc 是 C 语言中的标准库函数,用于在堆上分配指定大小的内存块,不会调用对象的构造函数,返回的是 void* 类型的指针,需要手动进行类型转换。
int main() {int* ptr = (int*)malloc(sizeof(int));*ptr = 5;std::cout << *ptr << std::endl;free(ptr);return 0;
}
内存分配失败处理:malloc返回NULL;new抛出std::bad_alloc异常
2、delete 和 free 分别用于什么场景?
delete 是 C++ 中的运算符,用于释放由 new 分配的内存,并调用对象的析构函数。
#include <iostream>
class MyClass {
public:~MyClass() {std::cout << "Destructor called" << std::endl;}
};
int main() {MyClass* obj = new MyClass();delete obj;return 0;
}
free 是 C 语言中的标准库函数,用于释放由 malloc、calloc 或 realloc 分配的内存,不会调用对象的析构函数。
#include <iostream>
#include <cstdlib>
int main() {int* ptr = (int*)malloc(sizeof(int));free(ptr);return 0;
}
3、new与malloc的关联
new通过调用operator new分配内存,而默认的operator new内部使用malloc
void* operator new(size_t size) { void* p = malloc(size); if (!p) throw std::bad_alloc(); return p;
}
4、delete NULL或nullptr会发生什么?
| 操作 | 空指针(NULL/nullptr) | 非空指针 |
|---|---|---|
delete / delete[] | 安全(无操作) | 需确保指针有效且未被重复释放 |
free | 安全(无操作) | 需确保内存由 malloc 分配 |
底层逻辑:编译器会检查指针是否为空,若为空则直接跳过析构和内存释放步骤
最佳实践:释放后立即置空指针
delete、free并不会把指针置空。
int* p = new int(10);
delete p; // 第一次释放
delete p; // 危险!重复释放非空指针
安全性:避免程序员在调用 delete 或 free 前必须显式检查指针是否为空(避免冗余检查)。
二、进阶
1、new[] 和 delete[] 的作用是什么?
new[] 用于在堆上动态分配数组内存,并对数组中的每个元素调用构造函数。delete[] 用于释放由 new[] 分配的数组内存,并对数组中的每个元素调用析构函数
include <iostream>
class MyClass {
public:MyClass() {std::cout << "Constructor called" << std::endl;}~MyClass() {std::cout << "Destructor called" << std::endl;}
};
int main() {MyClass* arr = new MyClass[3];delete[] arr;return 0;
}
C++ 编译器在解析代码时会忽略
delete和[]之间的所有空白符(包括空格、换行符、制表符等),推荐delete[]的紧凑写法delete[]arr; delete []arr; delete [] arr; delete[] arr;
2、对于内置数据类型,使用delete、delete[]效果是一样的。这句话对吗?为什么?
内置类型无析构函数:C++ 的内置数据类型(如 int、long、指针等)没有析构函数。delete 和 delete[] 的核心差异在于是否调用析构函数,而内置类型无需析构,但内存释放的完整性仍取决于运行时环境。某些编译器(如 MSVC)可能通过内存池机制自动回收整个数组内存,但这属于未定义行为,不可依赖。
int* p1 = new int(10);
delete p1; // 正确释放单个对象
int* p2 = new int[10];
delete[] p2; // 正确释放数组
delete p2; // 未定义行为
分配时的元数据记录:无论是 new 还是 new[],内存分配时系统会记录分配的内存大小和对象数量(存储在 _CrtMemBlockHeader 等结构中)。释放时,delete 和 delete[] 均能通过指针获取这些信息,从而正确释放连续内存块 。
int* p = new int[1000];
delete p; // 看似正常,但 Valgrind 报告 3996 字节泄漏(1000 * 4 - 4)
+-------------------+
| 数组长度(1000) | ← 元信息(通常占用 4/8 字节)
+-------------------+
| 元素0(int) | ← 用户可见的指针 `p` 指向此处
+-------------------+
| 元素1(int) |
+-------------------+
| ...(共 1000 个) |
+-------------------+
3、使用 new 分配内存,用 free 释放会怎么样?
如果使用 new 分配内存,却用 free 释放,对象的析构函数不会被调用,可能会导致资源泄漏,例如对象中包含动态分配的资源(如文件句柄、网络连接等)无法正确释放。
#include <iostream>
class MyClass {
public:~MyClass() {std::cout << "Destructor called" << std::endl;}
};
int main() {MyClass* obj = new MyClass();free(obj); // 析构函数不会被调用return 0;
}
4、 使用 malloc 分配内存,用 delete 释放会怎么样?
delete 会尝试调用对象的析构函数。 malloc 分配的内存没有经过构造函数初始化,调用析构函数可能会导致未定义行为。
#include <iostream>
#include <cstdlib>class ResourceHolder {
public:ResourceHolder() {std::cout << "ResourceHolder: Acquiring resource..." << std::endl;// 模拟资源获取,例如打开文件、分配内存等resource = new int[100];}~ResourceHolder() {std::cout << "ResourceHolder: Releasing resource..." << std::endl;// 模拟资源释放,例如关闭文件、释放内存等delete[] resource;}private:int* resource;
};int main() {// 使用 malloc 分配内存ResourceHolder* holder = (ResourceHolder*)malloc(sizeof(ResourceHolder));if (holder == nullptr) {std::cerr << "Memory allocation failed!" << std::endl;return 1;}// 尝试使用 delete 释放内存delete holder;return 0;
}
- 运用
malloc为ResourceHolder对象分配内存。malloc只是单纯地分配指定大小的内存块,不会调用对象的构造函数,所以resource指针不会被正确初始化。 - 尝试使用
delete释放内存。delete会调用对象的析构函数,但是由于resource指针未被正确初始化,在析构函数中调用delete[] resource就会引发未定义行为,可能会导致程序崩溃或者出现其他不可预测的问题。- 当
delete[] resource尝试释放一个未正确初始化的指针时,可能会访问非法内存地址,从而致使程序崩溃。
- 当
5、malloc + delete混用问题
注:new和delete必须成对使用
- 内存生命周期管理:
new与delete通过构造函数/析构函数保证对象完整生命周期 - 混用风险:未调用析构函数(若对象有资源需释放)
class MyClass {int* data; // 未初始化
public:MyClass() { data = new int[100]; } // 构造函数未执行!~MyClass() { delete[] data; } // 析构函数尝试释放野指针
};MyClass* p = (MyClass*)malloc(sizeof(MyClass));
delete p; // 析构函数调用delete[] data,但data未初始化 → 崩溃
delete确实会调用析构函数,但这一行为是否能正确执行,取决于对象是否被正确构造。通过malloc分配内存时,MyClass的构造函数未被调用,但delete p却尝试调用析构函数。若析构函数中存在对未初始化成员的操作(如delete data),会导致未定义行为(如访问野指针,引发崩溃)
内置类型(如
int):
无构造函数和析构函数,因此malloc+delete可能不会崩溃(因为没有析构操作),但仍是未定义行为int* p = (int*)malloc(sizeof(int)); delete p; // 可能不崩溃,但不符合规范
6、new与free混用
未调用析构函数,且可能因内存布局差异导致崩溃(如new[]的头部信息未处理)
当通过new[]分配数组时,内存布局可能包含头部信息(记录数组长度),例如:
MyClass* arr = new MyClass[5];
// 内存布局:[长度=5][对象1][对象2]...[对象5]
delete[]会根据头部信息调用5次析构函数,再释放完整内存块。若用free释放,头部信息未被处理。free 的输入是 arr(指向第一个对象),但 new[] 分配的实际内存块起始地址是 arr - sizeof(头部)。
正确行为:若用户调用 delete[] arr,会从头部地址释放完整内存块(包括头部和所有对象)。错误行为:若调用 free(arr),free 仅尝试释放从 arr 开始的地址,而实际分配的内存块起始位置未被正确识别,导致部分内存未被释放(内存泄漏)或堆结构破坏(可能崩溃)
free(arr) 无法识别 new[] 的内存布局,会释放不完整的地址范围,导致内存泄漏(头部和部分对象未被释放),甚至因堆管理器元数据损坏而崩溃。
注:不是只释放了[长度=5]
[对象1][对象2]...[对象5]
free只能释放通过malloc/calloc/realloc分配的内存块,其底层通过内存块的头部元数据(如大小信息)来释放整个内存块。
new[]分配的头部信息可能格式与malloc不同,导致free无法正确解析,最终释放的地址范围是未定义的:
- 可能释放不完整:
free(arr)可能仅释放从对象0地址开始的部分内存(如对象0的存储空间),而头部和其他对象的内存未被释放- 可能破坏堆结构:错误释放地址会导致堆管理器元数据损坏,引发后续内存操作崩溃
若编译器未添加头部信息,free(arr) 可能释放整个数组(因内存块连续),但这是未定义行为,依赖具体实现。(内置类型数组)
- 析构函数未被调用 → 资源泄漏。
- 释放的地址错误(如未回退到头部起始位置)→ 内存布局破坏,可能崩溃
三、高阶
1、如何重载 new 和 delete 运算符?
应用场景:
- 内存池优化(减少碎片)
- 调试内存泄漏(记录分配/释放日志)
#include <iostream>
#include <cstdlib>
class MyClass {
public:static void* operator new(size_t size) {std::cout << "Custom new operator called" << std::endl;return std::malloc(size);}static void operator delete(void* ptr) {std::cout << "Custom delete operator called" << std::endl;std::free(ptr);}~MyClass() {std::cout << "Destructor called" << std::endl;}
};
int main() {MyClass* obj = new MyClass();delete obj;return 0;
}
2、 如何捕获new过程异常并处理
int main() {try {while (true) {int* ptr = new int[1000000];}} catch (const std::bad_alloc& e) {std::cout << "Memory allocation failed: " << e.what() << std::endl;}return 0;
}
3、 delete和delete[]有何区别?
delete释放单个对象;delete[]释放数组
delete调用一次析构函数;delete[]对数组中每个元素调用析构函数
对数组使用delete会导致内存泄漏或崩溃。
4、new[]如何知道要调用多少次析构函数?
头部信息存储:当分配自定义类型数组时,new[]会在内存块头部额外存储数组长度(如4/8字节)
delete[]根据头部信息确定析构次数,再释放完整内存块
MyClass* arr = new MyClass[5];
// 内存布局:[长度=5][对象1][对象2]...[对象5]
delete[] arr; // 读取长度5,调用5次析构函数
内置类型数组:若数组元素是基本类型(如 int),某些编译器可能不添加头部信息(因无需调用析构函数),直接分配连续内存
5、设计一个内存泄漏检测工具,如何跟踪new/delete的使用?
重载全局operator new/delete:记录分配/释放的地址和大小。
哈希表跟踪:维护分配记录,检测未配对的new和delete
std::map<void*, size_t> allocMap;
void* operator new(size_t size) { void* p = malloc(size); allocMap[p] = size; return p;
}
void operator delete(void* p) { if (allocMap.erase(p)) free(p); else logLeak(); // 检测到未记录释放
}
相关文章:
[C++面试] new、delete相关面试点
一、入门 1、说说new与malloc的基本用途 int* p1 (int*)malloc(sizeof(int)); // C风格 int* p2 new int(10); // C风格,初始化为10 new 是 C 中的运算符,用于在堆上动态分配内存并调用对象的构造函数,会自动计算所需内存…...
一周学会Pandas2 Python数据处理与分析-Jupyter Notebook安装
锋哥原创的Pandas2 Python数据处理与分析 视频教程: 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Jupyter (Project Jupyter | Home)项目是一个非营利性开源项目,于2014年由IPython项目中诞生…...
第30周Java分布式入门 消息队列 RabbitMQ
RabbitMQ章节介绍 一、RabbitMQ概述 RabbitMQ学习内容: 本章节将学习RabbitMQ的概念、安装启动、管理后台、代码实操、交换机工作模式以及Spring Boot整合RabbitMQ。消息队列定义: 消息队列是一种用于在分布式系统中传递消息的机制。消息队列特性: 消息队列具有异步、解耦、削…...
北斗导航 | THE GNSS AMBIGUITY RATIO-TEST REVISITED: A BETTER WAY OF USING IT【论文要点】
THE GNSS AMBIGUITY RATIO-TEST REVISITED: A BETTER WAY OF USING IT 总结该论文的核心贡献及关键方法如下:论文核心内容概述 传统比率测试的局限性 传统比率测试通过比较最优与次优模糊度解的残差平方和比值(即 R = q (...
MySQL 面试知识点详解(索引、存储引擎、事务与隔离级别、MVCC、锁机制、优化)
一、索引基础概念 1 索引是什么? 定义:索引是帮助MySQL高效获取数据的有序数据结构,类似书籍的目录。核心作用:减少磁盘I/O次数,提升查询速度(以空间换时间)。 2 索引的优缺点 优点缺点加速…...
Linux / Windows 下 Mamba / Vim / Vmamba 安装教程及安装包索引
目录 背景0. 前期环境查询/需求分析1. Linux 平台1.1 Mamba1.2 Vim1.3 Vmamba 2. Windows 平台2.1 Mamba2.1.1 Mamba 12.1.2 Mamba 2- 治标不治本- 终极版- 高算力版 2.2 Vim- 治标不治本- 终极版- 高算力版 2.3 Vmamba- 治标不治本- 终极版- 高算力版 3. Linux / Windows 双平…...
deepseek v3-0324 Markdown 编辑器 HTML
Markdown 编辑器 HTML 以下是一个美观的 Markdown 编辑器 HTML 页面,支持多种主题切换和实时预览功能: <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&q…...
视频设备轨迹回放平台EasyCVR如何搭建公共娱乐场所远程视频监控系统
一、背景介绍 由于KTV、酒吧、足疗店等服务场所人员流动频繁、环境复杂,一直是治安管理的重点区域。为有效打击 “黄赌毒”、打架斗殴、寻衅滋事等违法犯罪的活动,打造安全有序的娱乐消费环境,我国相关部门将加大对这类场所的清查与管控力度…...
网络安全基础知识总结
什么是网络安全 采取必要措施,来防范对网络的攻击,侵入,干扰,破坏和非法使用,以及防范一些意外事故,使得网络处于稳定可靠运行的状态,保障网络数据的完整性、保密性、可用性的能力(CIA)。 举例…...
Python设计模式:克隆模式
1. 什么是克隆模式 克隆模式的核心思想是通过复制一个已有的对象(原型)来创建一个新的对象(克隆)。这种方式可以避免重复的初始化过程,从而提高效率。克隆模式通常涉及以下几个方面: 原型对象:…...
【工具】在 Visual Studio 中使用 Dotfuscator 对“C# 类库(DLL)或应用程序(EXE)”进行混淆
在 Visual Studio 中使用 Dotfuscator 进行混淆 Dotfuscator 是 Visual Studio 自带的混淆工具(Dotfuscator Community Edition,简称 CE)。它可以混淆 C# 类库(DLL)或应用程序(EXE),…...
积分赛——获取环境温度
设计要求 从DS18B20温度传感器上获取环境温度,并将其温度值显示到数码管上(保留两位小数)。 当“S4”定义为发送按键,按键S4按下时,串口向PC端发送当前采集的温度值; 串口发送格式: Temp:26.…...
LogicFlow获取锚点数据的自定义key并添加的连接的Edge边数据中
1、重写 PolylineEdgeModel 类(其它 EdgeModel 都可以) class CustomNetWorkNodeEdge extends PolylineEdge { } class CustomNetWorkNodeEdgeModel extends PolylineEdgeModel {getData() {const data super.getData();//获取开始锚点自定义属性添加到…...
【python中级】解压whl文件内容
【python中级】解压whl文件内容 1.背景2.解压1.背景 【python中级】关于whl文件的说明 https://blog.csdn.net/jn10010537/article/details/146979236 补充以上博客: 在 旧版 setuptools 中(< v58),如果想生成 .whl,必须先pip install 安装 wheel 三方包! pip inst…...
Xilinx系列FPGA实现HDMI2.1视频收发,支持8K@60Hz分辨率,提供2套工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我已有的4K/8K视频处理解决方案我已有的FPGA图像处理方案 3、详细设计方案设计框图硬件设计架构本HDMI2.1性能参数8K视频输入源Video PHY ControllerHDMI 2.1 Receive…...
如何把网页文章转为pdf保存
fnF12调出右边网页端的控制台 在下面输入代码 1、转CSDN上的文章 (function(){ use strict;var articleBox $("div.article_content");articleBox.removeAttr("style");var head_str ""; var foot_str ""; var olde…...
开源可视化大屏go-view前后端安装
一、后端安装 下载代码 git clone https://gitee.com/MTrun/go-view-serve修改配置 cd go-view-serve/ # 修改application-dev.yml的数据库文件地址 vi ./src/main/resources/application-dev.ymlapplication-dev.yml spring:datasource:driver-class-name: org.sqlite.JDB…...
eventEmitter实现
没有做任何异常处理,简单模拟实现 事件对象的每一个事件都对应一个数组 /*__events {"事件1":[cb1,cb2],"事件2":[cb3,cb4],"事件3":[...],"事件4":[...],};*/class E{__events {};constructor(){}//注册监听回调on(type , callbac…...
自然语言处理|如何用少样本技术提升低资源语言处理?
一、引言 在全球化的背景下,自然语言处理(NLP)技术取得了显著进展,为人们的生活和工作提供了便利。然而,大多数 NLP 研究和应用集中在少数高资源语言上,如英语和中文。据统计,全球存在超过 700…...
系统安全——文件监控-FileMonitor
namespace FileSystemWatcherDemo {public partial class Form1 : Form{ public Form1(){InitializeComponent();UsingFileSystemWatcher();} /// <summary>/// 使用FileSystemWatcher方法/// </summary>void UsingFileSystemWatcher(){//6.2//FileSystemWa…...
07-01-自考数据结构(20331)- 排序-内部排序知识点
内部排序算法是数据结构核心内容,主要包括插入类(直接插入、希尔)、交换类(冒泡、快速)、选择类(简单选择、堆)、归并和基数五大类排序方法。 知识拓扑 知识点介绍 直接插入排序 定义:将每个待排序元素插入到已排序序列的适当位置 算法步骤: 从第二个元素开始遍历…...
Unity:平滑输入(Input.GetAxis)
目录 1.为什么需要Input.GetAxis? 2. Input.GetAxis的基本功能 3. Input.GetAxis的工作原理 4. 常用参数和设置 5. 代码示例:用GetAxis控制角色移动 6. 与Input.GetAxisRaw的区别 7.如何优化GetAxis? 1.为什么需要Input.GetAxis&…...
【AI学习】MCP的简单快速理解
最近,AI界最火热的恐怕就是MCP了。作为一个新的知识点,学习的开始,先摘录一些信息,从发展历程、通俗介绍到具体案例,这样可以快速理解MCP。 MCP发展历程 来自i陆三金 Anthropic 开发者关系负责人 Alex Albert&#…...
单机快速部署开源、免费的分布式任务调度系统——DolphinScheduler
看了DolphinScheduler的介绍,不知道有没有引起你的兴趣,有没有想要上手体验一番呢。本文则主要为大家介绍DolphinScheduler的单机部署方式,方便大家快速体验。 环境准备 需要Java环境,这是一个老生常谈的问题,关于Ja…...
Vue3命名规范指南
在 Vue 3 中,遵循一致的命名规范可以提高代码的可读性和维护性。以下是常见的命名规范和实践建议: 1. 组件命名 PascalCase(大驼峰式) 单文件组件(.vue 文件)和组件引用时推荐使用 PascalCase,便…...
【大模型系列篇】大模型基建工程:基于 FastAPI 自动构建 SSE MCP 服务器
今天我们将使用FastAPI来构建 MCP 服务器,Anthropic 推出的这个MCP 协议,目的是让 AI 代理和你的应用程序之间的对话变得更顺畅、更清晰。FastAPI 基于 Starlette 和 Uvicorn,采用异步编程模型,可轻松处理高并发请求,尤…...
springcloud configClient获取configServer信息失败导致启动configClient注入失败报错解决
目录 一、问题现象 二、解决方案 三、运行结果 四、代码地址 一、问题现象 springcloud configClient获取configServer信息失败导致启动configClient注入失败 报错堆栈信息 org.springframework.beans.factory.BeanCreationException: Error creating bean with name scop…...
HarmonyOS-ArkUI Rcp模块类关系梳理
前言 本文重点解决的是,按照官网学习路径学习Tcp模块内容时,越看越混乱的问题。仿照官网案例,书写代码时,产生的各种疑惑。比如,类与类之间的关系,各种配置信息究竟有多少,为什么越写越混乱。那…...
26考研——线性表_ 线性表的链式表示_双循环链表(2)
408答疑 文章目录 三、 线性表的链式表示双循环链表单链表与双链表的比较单链表的特点双链表的特点 双链表上基本操作的实现双链表的插入操作双链表的删除操作 双链表的代码实操定义结点创建一个结点带头结点的双链表初始化创建双链表打印双链表查找结点插入结点在指定节点后插…...
大模型如何引爆餐饮与电商行业变革
大模型如何引爆餐饮与电商行业变革? 一、时代背景:大模型重构产业逻辑的底层动力 1. 技术跃迁催生效率革命 2025年,大模型技术迎来"普惠临界点"。李开复在中关村论坛指出,大模型推理成本每年降低10倍,使得…...
