C++的write
.obj文件的数量与.cpp文件的数量一致
强制类型转换的运算优先级比乘除高
在C++语言中, %运算符要求运算数必须是整型。是否正确? .
cerr 是 ostream 类的对象,用于标准错误输出,不是输入流对象
cin 是 istream 类的对象,用于标准输入,是正确答案
clog 是 ostream 类的对象,用于标准日志输出,不是输入流对象
cout 是 ostream 类的对象,用于标准输出,不是输入流对象
C++位运算的符号
构造函数没有返回值类型
“||”是短路运算符,当左操作数为true(非0)时,右操作数就不会被执行
内存泄漏的核心定义是:程序中动态分配的内存(如通过new、malloc等分配)在不再需要时,未被正确释放,且程序失去了对该内存的引用(即无法再通过任何指针访问这块内存),导致这部分内存被永久占用,直到程序结束才会被操作系统回收。
常见场景包括:
- 忘记释放内存:如
new了对象但未delete,malloc了内存但未free。 - 指针被意外修改:如指针重新赋值(指向其他地址),导致原内存地址丢失。
- 异常安全问题:在
new之后、delete之前发生异常,导致delete语句未执行。 - 容器未清空:如
std::vector中存储了动态分配的指针,容器销毁时未手动释放这些指针指向的内存。 shared_ptr循环引用:如两个shared_ptr互相引用,导致引用计数无法归零,对象内存无法释放。
检测方式:
- 工具检测:使用Valgrind(Linux)、Visual Leak Detector(Windows)、Clang的AddressSanitizer等工具,可定位泄漏的内存位置和分配点。
- 代码审查:重点检查动态内存分配与释放的配对情况,尤其是分支语句和异常处理块。
避免方式:
- 优先使用智能指针(
unique_ptr、shared_ptr),减少手动new/delete。 - 尽量使用标准容器(如
vector、string)替代手动管理的数组/字符串。 - 遵循RAII(资源获取即初始化)原则,将资源封装在对象中,利用对象生命周期自动管理资源。
- 编写异常安全的代码,确保在任何分支(包括异常抛出)都能正确释放资源。
追问:什么是RAII?它在C++内存管理中起到了怎样的作用?
delete一个空指针(nullptr)是安全的,不会产生任何副作用。
原因是 C++ 标准明确规定:对空指针执行delete或delete[]是合法操作,相当于无操作(no-op)。这是因为delete的内部实现会先检查指针是否为空,若为空则直接返回,不会尝试访问任何内存或执行释放操作。
你提到的 “重复释放” 是指对非空的已释放指针再次执行delete(此时指针可能成为野指针),这会导致未定义行为(如内存 corruption)。但空指针本身不指向任何内存,因此delete空指针不存在此类问题。
重载operator new和operator delete的核心目的是自定义内存分配策略,以满足特定场景的需求,常见情况包括:
性能优化:对于频繁创建和销毁的小对象(如链表节点、短字符串),默认内存分配器可能因碎片化或开销大导致效率低。此时可重载为内存池(预先分配一块大内存,按需分割使用),减少系统调用次数。
内存跟踪与调试:重载后可在分配 / 释放时记录日志(如内存地址、大小、调用栈),用于检测内存泄漏、重复释放等问题(类似调试工具的功能)。
内存限制与统计:例如限制某类对象的最大分配数量,或统计其总内存占用,通过重载在分配时检查并控制。
对齐要求:某些硬件或库可能要求内存按特定字节对齐(如 16 字节对齐用于 SIMD 指令),默认分配器未必满足,重载可确保内存对齐。
举例:实现一个简单的内存池管理某类Node的内存,operator new从预分配的内存块中分配空间,operator delete将空间放回内存池而非直接归还给系统,提升频繁创建销毁Node的效率。
const修饰成员函数时,本质是将this指针变为const 类名* const类型(既不能通过this修改成员变量,也不能让this指向其他对象)。
不能修改非mutable修饰的成员变量;
不能调用同类的非const成员函数(避免通过非const函数间接修改成员);
可以被非const对象和const对象调用,但非const成员函数只能被非const对象调用。
deque的核心定位是兼顾 “两端快速操作” 和 “相对高效的随机访问”。它的迭代器虽然复杂,但相比list,避免了遍历查找的 O (n) 开销(通过 map 数组能快速定位缓冲区);相比vector,又解决了头部插入 / 删除时的 O (n) 数据移动问题(只需新增头部缓冲区,无需挪动已有元素)。
这种 “分段连续 + 复杂迭代器” 的取舍,本质是为了平衡 “两端操作效率” 和 “随机访问能力”—— 比如在实现队列(FIFO)或双端队列(deque 本身就是双端队列的实现)时,需要频繁在头部和尾部操作,deque的性能就会显著优于vector(头部操作无拷贝)和list(随机访问无遍历开销)。