面试题答案
一键面试1. std::unique_ptr
- 特点:
- 独占式拥有资源,同一时间只有一个
std::unique_ptr
可以指向给定对象。 - 不能复制,只能移动。移动语义使得对象的所有权能够高效转移。
- 内存释放时机:当
std::unique_ptr
离开其作用域时,会自动释放所指向的对象。
- 独占式拥有资源,同一时间只有一个
- 适用场景:
- 当你希望某个对象只有一个所有者,并且对象的生命周期与所有者的生命周期紧密相关时使用。例如,管理动态分配的数组或资源(如文件句柄等),其所有权不应被共享。
- 作为函数返回值,高效地转移对象所有权。
- 解决内存泄漏问题:通过RAII(Resource Acquisition Is Initialization)机制,在
std::unique_ptr
对象析构时,自动调用其指向对象的析构函数来释放资源,从而避免手动管理内存导致的内存泄漏。
2. std::shared_ptr
- 特点:
- 共享式拥有资源,多个
std::shared_ptr
可以指向同一个对象。 - 采用引用计数机制来管理对象的生命周期。
- 支持复制和赋值操作,复制或赋值时,引用计数会相应增加或减少。
- 共享式拥有资源,多个
- 适用场景:
- 当需要多个对象共享同一资源,并且希望资源在没有任何对象使用它时自动释放时使用。例如,在多线程环境下,多个线程可能需要访问同一个共享资源,
std::shared_ptr
可以安全地管理该资源的生命周期。 - 用于实现对象的共享所有权,如在链表、树等数据结构中,不同节点可能需要共享某些子节点或数据。
- 当需要多个对象共享同一资源,并且希望资源在没有任何对象使用它时自动释放时使用。例如,在多线程环境下,多个线程可能需要访问同一个共享资源,
- 解决内存泄漏问题:借助引用计数机制,当引用计数降为0时,表明没有任何
std::shared_ptr
指向该对象,此时自动释放对象所占用的内存,防止内存泄漏。
3. std::weak_ptr
- 特点:
- 弱引用,不控制对象的生命周期,不会增加对象的引用计数。
- 可以从
std::shared_ptr
创建,用于解决循环引用问题。 - 可以通过
lock()
成员函数尝试获取一个std::shared_ptr
,如果对象已经被释放,lock()
返回一个空的std::shared_ptr
。
- 适用场景:
- 解决循环引用问题,例如在双向链表或树形结构中,避免因相互引用导致对象无法释放。
- 当你需要观察一个对象,但不希望影响其生命周期时使用,比如缓存机制,观察对象是否存在,但不干预其销毁。
- 解决内存泄漏问题:通过不增加引用计数,打破循环引用,使得对象在没有强引用(
std::shared_ptr
)时能够正常释放,从而避免内存泄漏。
4. std::shared_ptr引用计数机制工作原理
- 初始化:当创建一个
std::shared_ptr
指向一个新对象时,该对象会关联一个引用计数器,初始值为1。 - 复制和赋值:当进行
std::shared_ptr
的复制或赋值操作时,引用计数器会增加。例如,将一个std::shared_ptr
赋值给另一个std::shared_ptr
,或者使用std::shared_ptr
作为函数参数传递(会发生复制),都会使引用计数加1。 - 析构:当一个
std::shared_ptr
对象析构时,其引用计数器会减1。如果引用计数减为0,表明没有任何std::shared_ptr
再指向该对象,此时会自动调用对象的析构函数释放对象所占用的内存,同时释放与该对象关联的引用计数等控制块。如果引用计数不为0,说明还有其他std::shared_ptr
指向该对象,对象不会被释放。