Skip to content

Cpp面试

benhao edited this page Jun 1, 2025 · 5 revisions

C++编译与内存相关

C++内存管理

堆与栈

C++ 内存管理:堆与栈详解

在 C++ 中,堆(Heap)栈(Stack) 是两种核心的内存分配区域,它们在生命周期、管理方式、性能和使用场景上有显著区别。


1. 栈(Stack)

  • 特点

    • 自动管理:由编译器自动分配和释放(函数结束时自动弹出)。
    • 速度快:仅需移动栈指针(硬件优化)。
    • 大小固定:通常较小(默认 1-8 MB,依赖系统和编译器)。
    • 局部性:存储函数参数、局部变量、返回地址等。
    • 连续内存:内存地址连续分配(高效缓存利用)。
  • 示例

    void foo() {
        int a = 10;          // a 在栈上
        char buffer[256];    // buffer 在栈上
    } // 函数结束,a 和 buffer 自动释放
  • 限制

    • 大对象(如巨型数组)可能导致栈溢出
    • 生命周期仅限于作用域内(无法跨函数传递所有权)。

2. 堆(Heap)

  • 特点

    • 手动管理:需显式分配(new/malloc)和释放(delete/free)。
    • 速度慢:需搜索可用内存块(可能触发系统调用)。
    • 空间大:仅受系统可用内存限制(GB 级别)。
    • 全局性:可在任何地方访问(通过指针)。
    • 非连续内存:动态分配(可能产生内存碎片)。
  • 示例

    void bar() {
        int* p = new int(42);   // 堆上分配 int
        std::vector<int>* vec = new std::vector<int>(1000); // 堆上分配对象
        // ... 使用 p 和 vec ...
        delete p;               // 手动释放
        delete vec;
    }
  • 风险

    • 内存泄漏:忘记 delete
    • 悬空指针:访问已释放内存。
    • 碎片化:频繁分配/释放导致内存利用率降低。

3. 关键对比

特性 栈(Stack) 堆(Heap)
管理方式 编译器自动管理 程序员手动管理(new/delete
速度 极快(移动栈指针) 较慢(搜索可用内存)
大小限制 小(默认 MB 级) 大(仅限系统内存)
生命周期 作用域内(函数结束即释放) 直到显式释放
内存布局 连续地址 碎片化(非连续)
使用场景 局部变量、小型数据 大对象、动态数据结构、跨函数共享
错误风险 栈溢出 内存泄漏、悬空指针、碎片化

4. 代码示例分析

#include <iostream>
#include <vector>

void stackExample() {
    int x = 5;                  // 栈分配
    std::vector<int> arr(100);   // arr 对象在栈上,内部数据在堆上
} // x 和 arr 自动释放(arr 的析构函数释放内部堆内存)

void heapExample() {
    int* y = new int(10);        // 堆分配
    std::vector<int>* vec = new std::vector<int>(1000); // 对象本身在堆上
    // ... 使用 y 和 vec ...
    delete y;                    // 必须手动释放!
    delete vec;                  // 否则内存泄漏
}

int main() {
    stackExample();  // 安全:无内存泄漏
    heapExample();   // 风险:若忘记 delete 则泄漏
    return 0;
}

5. 最佳实践

  1. 优先使用栈

    • 小型对象和局部变量。
    • 避免栈溢出(避免巨型栈分配)。
  2. 智能指针管理堆

    #include <memory>
    void safeHeap() {
        auto ptr = std::make_unique<int>(30); // 自动释放
        auto arr = std::make_shared<std::vector<int>>(100); // 引用计数
    } // 无需 delete
  3. 避免裸指针:用 std::vector 替代动态数组,用 std::string 替代 char*

  4. 栈溢出防范

    • 递归时控制深度。
    • 大对象改用堆(如 std::vector 存储大量数据)。

6. 常见问题

  • Q:newmalloc 的区别?
    new 调用构造函数,malloc 仅分配内存;delete 调用析构函数,free 仅释放内存。

  • Q:如何检测内存泄漏?
    使用工具:Valgrind(Linux)、AddressSanitizer(GCC/Clang)、Visual Studio 诊断工具。

  • Q:对象成员存储在堆还是栈?
    对象本身的位置决定其成员位置:

    class MyClass {
        int a;          // 若 MyClass 在栈上,则 a 在栈上
        int* b;         // b(指针)在栈上,但 *b 指向堆内存
    };

总结

  • :自动、快速、安全,适合小型临时数据。
  • :灵活、大容量,需谨慎管理,适合动态生命周期数据。
  • 现代 C++ 准则:用智能指针和容器(如 std::vector)减少裸堆操作!

变量定义与生存周期

内存对齐

智能指针简介与使用

智能指针的创建

编译与链接

大端与小端

内存泄漏

内存泄露检测与预防

include ""和<>的区别

C++ 语言对比

C 和 C++ 的对比

Java 和 C++ 的对比

Python 和 C++ 的对比

Go 和 C++ 的对比

Rust 和 C++ 的对比

C++ 11 新特性

C++ 14, C++ 17 新特性

C++ 关键字与关键库函数

sizeof 和 strlen 的区别

lambda 表达式的应用

explicit 的作用

C 和 C++ static 中的作用

const 作用及用法

define 和 const 的区别

define 和 typedef 的区别

用宏实现比较大小,以及两个数中的最小值

inline 作用及使用方法

inline 函数工作原理

宏定义(define)和内联函数(inline)的区别

new 的作用

new 和 malloc 的区别

delete 与 free 的区别

C 和 C++ struct 的区别

struct 和 union 的区别

class 和 struct 的异同

volatile 的作用与使用场景

返回函数中静态变量的地址会发生什么

extern C 的作用

sizeof(1==1) 在 C 和 C++ 中的结果

memmove 函数的底层原理

strcpy 函数的缺陷

auto 类型推导的原理

C++ 面向对象

面向对象及其三大特性

重载、重写、隐藏的区别

多态及其实现方法

对象创建限制在堆或栈

C++ 模板编程

虚函数和纯虚函数详解

虚函数和纯虚函数的区别

虚函数的实现机制

单继承和多继承的虚函数表结构

如何禁止构造函数的使用

什么是类的默认构造函数

构造函数、析构函数是否可以定义成虚函数

如何避免拷贝

如何减少构造函数开销

多重继承的常见问题及避免方法

空类字节数及对应生成的成员函数

类的大小

为什么拷贝构造函数必须声明为引用

C++ 类对象的初始化顺序

如何禁止一个类被实例化

成员初始化列表效率高的原因

实例化一个对象需要哪几个阶段

友元函数的作用及使用场景

静态绑定和动态绑定的实现

深拷贝和浅拷贝的区别

编译时多态和运行时多态的区别

不允许修改类的成员变量的函数实现方法

如何让类不能被继承

C++ 语言特性相关

左值和右值:区别、引用及转化

std::move() 函数的实现原理

指针及其大小、用法

野指针和悬空指针详解

C++ 11 nullptr 比 NULL 的优势比较

指针和引用的区别

常量指针和指针常量的区别

函数指针的定义

强制类型转换的类型

结构体相等的判断方式及 memcmp 函数的使用

参数传递中:值传递、引用传递、指针传递的区别

模板及其实现

函数模板和类模板的区别

什么是可变参数模板

什么是模板特化

switch 的 case 里为何不建议定义变量

迭代器的作用

泛型编程如何实现

什么是类型萃取

C++ I/O 与进程同步

C++ I/O 操作

线程同步与异步

C++ 互斥信号量

C++ 条件变量

设计模式

常见设计模式

单例模式及其实现

工厂模式及其实现

观察者模式及其实现

Clone this wiki locally