MST

星途 面试题库

面试题:C++ 中智能指针在内存管理中的应用

请简述C++中智能指针(如std::unique_ptr、std::shared_ptr、std::weak_ptr)的特点及它们是如何解决内存管理问题的。并且举例说明在实际项目中,如何使用std::shared_ptr和std::weak_ptr来避免循环引用导致的内存泄漏。
18.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

智能指针特点及解决内存管理问题方式

  1. std::unique_ptr
    • 特点
      • 独占式拥有对象的所有权,同一时间只能有一个std::unique_ptr指向一个对象。
      • 不能进行拷贝构造和拷贝赋值,但可以进行移动构造和移动赋值。
      • 析构时会自动释放所指向的对象。
    • 解决内存管理问题方式:通过在析构函数中释放所指向的对象,确保对象在生命周期结束时被正确释放,避免手动释放内存可能导致的内存泄漏。例如,在函数内部创建一个std::unique_ptr,当函数结束时,std::unique_ptr自动析构,释放其所指向的内存。
  2. std::shared_ptr
    • 特点
      • 共享式拥有对象的所有权,多个std::shared_ptr可以指向同一个对象。
      • 使用引用计数机制,记录指向同一对象的std::shared_ptr的数量。
      • 支持拷贝构造和拷贝赋值。
    • 解决内存管理问题方式:当引用计数变为0时,即没有std::shared_ptr指向该对象时,自动释放所指向的对象。这使得内存管理更加自动化,减少了手动管理内存的复杂性和出错几率。例如,在不同函数或对象之间传递std::shared_ptr,不用担心对象何时被释放,只要有std::shared_ptr存在,对象就不会被释放。
  3. std::weak_ptr
    • 特点
      • 弱引用指针,不增加对象的引用计数,它指向由std::shared_ptr管理的对象。
      • 可以通过lock()函数尝试获取指向对象的std::shared_ptr,如果对象已经被释放,则lock()返回一个空的std::shared_ptr
    • 解决内存管理问题方式:用于解决std::shared_ptr的循环引用问题,它不参与引用计数,因此不会导致对象无法释放。同时,通过lock()函数可以安全地访问对象,避免悬空指针问题。

使用std::shared_ptrstd::weak_ptr避免循环引用导致的内存泄漏示例

#include <iostream>
#include <memory>

class B;

class A {
public:
    std::weak_ptr<B> b_ptr;
    ~A() {
        std::cout << "A destroyed" << std::endl;
    }
};

class B {
public:
    std::weak_ptr<A> a_ptr;
    ~B() {
        std::cout << "B destroyed" << std::endl;
    }
};

void test() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();
    a->b_ptr = b;
    b->a_ptr = a;
}

int main() {
    test();
    // 此时a和b所指向的对象会被正确释放,不会出现内存泄漏
    return 0;
}

在上述代码中,AB类中分别使用std::weak_ptr来指向对方,而不是std::shared_ptr。这样,当test函数结束时,ab的引用计数都变为0,它们所指向的AB对象会被正确释放,避免了因循环引用导致的内存泄漏。如果AB类中使用std::shared_ptr相互指向,会导致循环引用,对象无法被释放。