MST

星途 面试题库

面试题:C++ 智能指针原理及内存管理

C++ 有 `std::unique_ptr`、`std::shared_ptr` 和 `std::weak_ptr` 三种智能指针,请解释它们各自的原理、适用场景及实现机制。假设存在一个复杂的对象层次结构,部分对象需要被多个地方共享,部分对象希望独占,如何合理使用这些智能指针来确保正确的内存管理并避免内存泄漏和悬空指针问题?
11.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

std::unique_ptr

  • 原理:独占所指向的对象,通过移动语义来转移所有权,不能进行拷贝构造和拷贝赋值,只能移动构造和移动赋值。当std::unique_ptr对象被销毁时,它所指向的对象也会被自动销毁。
  • 适用场景:适用于对象只需要被一个所有者管理的场景,比如函数内部创建的局部对象,该对象不需要在函数外部共享。
  • 实现机制:通常实现为一个封装了原始指针的类,内部重载了delete操作符来释放所指向的对象。当std::unique_ptr对象离开作用域时,析构函数会被调用从而释放内存。

std::shared_ptr

  • 原理:通过引用计数的方式来管理对象的生命周期。多个std::shared_ptr可以指向同一个对象,每当有新的std::shared_ptr指向该对象时,引用计数加1;当std::shared_ptr被销毁时,引用计数减1。当引用计数为0时,对象被自动销毁。
  • 适用场景:适用于对象需要被多个地方共享的场景,比如在多个模块间传递同一个对象的指针,并且这些模块都需要对该对象进行操作。
  • 实现机制:内部维护一个指向对象的指针以及一个指向引用计数的指针。构造、拷贝构造、赋值等操作会修改引用计数,析构函数会在引用计数为0时释放对象内存。

std::weak_ptr

  • 原理:它是一种弱引用,指向由std::shared_ptr管理的对象,但不增加引用计数。主要用于解决std::shared_ptr之间的循环引用问题。当std::shared_ptr管理的对象被销毁后,std::weak_ptr会自动变为空指针。
  • 适用场景:当存在可能导致循环引用的场景时,比如双向链表节点间的互相引用。也适用于需要检测对象是否存在但不影响其生命周期的场景。
  • 实现机制:内部也维护一个指向对象的指针,但没有直接增加引用计数的操作。通过lock()成员函数可以获取一个std::shared_ptr,如果对象已被销毁,lock()会返回一个空的std::shared_ptr

在复杂对象层次结构中的使用策略

  • 独占对象:对于希望独占的对象,使用std::unique_ptr。例如,在对象层次结构的叶子节点,如果这些叶子节点不需要被其他对象共享,std::unique_ptr可以有效地管理它们的生命周期,确保当包含它们的父对象销毁或离开作用域时,叶子节点对象也被正确销毁。
  • 共享对象:对于需要被多个地方共享的对象,使用std::shared_ptr。例如,在对象层次结构中有一些中间节点对象,多个分支都需要访问这些对象时,std::shared_ptr可以保证只要有任何一个地方还在使用该对象,它就不会被销毁。
  • 处理循环引用:如果对象层次结构中存在可能导致循环引用的情况,比如两个对象互相持有对方的引用,这时可以在其中一个方向上使用std::weak_ptr。例如,A对象持有B对象的std::shared_ptr,而B对象持有A对象的std::weak_ptr,这样就可以避免循环引用导致的内存泄漏问题。同时,B对象可以通过std::weak_ptrlock()函数来判断A对象是否还存在并获取其std::shared_ptr以进行操作。