MST

星途 面试题库

面试题:C++中堆内存管理的常见问题及解决方案

在C++使用堆内存进行开发时,经常会遇到内存泄漏、悬空指针等问题。请描述这些问题产生的原因,并给出至少两种有效的解决方案,同时结合代码示例说明如何避免这些问题。
49.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

问题产生原因

  1. 内存泄漏
    • 动态分配的内存(使用newmalloc等)在程序结束前没有使用deletefree释放。例如在循环中不断分配内存但未释放,随着循环次数增加,占用的内存越来越多,最终耗尽系统内存资源。
    • 异常处理过程中,已经分配的内存没有得到正确释放。比如在try块中分配内存,在catch块中处理异常时没有释放已分配的内存。
  2. 悬空指针
    • 指针所指向的内存已经被释放,但指针没有被设置为nullptr(在C++11及以后)或NULL(C++11之前)。之后如果继续使用该指针,就会导致未定义行为,因为它指向的内存已经无效。
    • 对象生命周期结束时,其成员指针没有被妥善处理。例如一个类的对象被销毁,但其内部的指针成员指向的内存没有释放,并且这个指针成员没有被置为nullptr,如果后续其他代码使用该指针成员,就会出现悬空指针问题。

解决方案及代码示例

  1. 智能指针(避免内存泄漏和悬空指针)
    • std::unique_ptr:独占式拥有所指向的对象,对象生命周期由std::unique_ptr控制。当std::unique_ptr离开作用域时,它所指向的对象会被自动释放。
    #include <iostream>
    #include <memory>
    
    void uniquePtrExample() {
        std::unique_ptr<int> ptr(new int(10));
        std::cout << "Value: " << *ptr << std::endl;
        // 离开作用域时,内存自动释放,无需手动delete
    }
    
    • std::shared_ptr:允许多个指针共享同一个对象。使用引用计数来跟踪有多少个std::shared_ptr指向同一个对象。当引用计数为0时,对象被自动释放。
    #include <iostream>
    #include <memory>
    
    void sharedPtrExample() {
        std::shared_ptr<int> ptr1(new int(20));
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "Value: " << *ptr2 << std::endl;
        // 当ptr1和ptr2离开作用域,引用计数降为0,内存自动释放
    }
    
  2. RAII(Resource Acquisition Is Initialization)原则(避免内存泄漏)
    • 通过在对象构造时获取资源(如分配内存),在对象析构时释放资源,将资源的生命周期与对象的生命周期绑定。
    #include <iostream>
    
    class Resource {
    public:
        Resource() {
            data = new int(30);
            std::cout << "Resource acquired" << std::endl;
        }
        ~Resource() {
            delete data;
            std::cout << "Resource released" << std::endl;
        }
        int getValue() {
            return *data;
        }
    private:
        int* data;
    };
    
    void raiiExample() {
        Resource res;
        std::cout << "Value: " << res.getValue() << std::endl;
        // res离开作用域时,自动调用析构函数释放内存
    }
    
  3. 手动释放并置空指针(避免悬空指针)
    • 在释放内存后,将指针设置为nullptr(C++11及以后)或NULL(C++11之前)。
    #include <iostream>
    
    void manualReleaseAndNullify() {
        int* ptr = new int(40);
        std::cout << "Value: " << *ptr << std::endl;
        delete ptr;
        ptr = nullptr;
        // 如果尝试访问ptr,会得到nullptr,而不是悬空指针导致的未定义行为
    }