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