面试题答案
一键面试可能导致内存泄漏的场景
- 忘记释放内存:在使用
new
分配内存后,没有对应的delete
语句。例如:
void memoryLeak1() {
int* ptr = new int;
// 这里没有delete ptr,导致内存泄漏
}
- 异常抛出时未释放内存:在分配内存后,执行过程中抛出异常,导致后续的
delete
语句未执行。
void memoryLeak2() {
int* ptr = new int;
// 假设这里抛出异常
throw std::exception();
delete ptr; // 由于异常,这行代码不会执行,内存泄漏
}
- 动态分配数组未正确释放:使用
new[]
分配数组内存,却用delete
而非delete[]
释放。
void memoryLeak3() {
int* arr = new int[10];
delete arr; // 应该用delete[] arr,否则会内存泄漏
}
使用智能指针避免内存泄漏及原理
std::unique_ptr
:- 避免内存泄漏方式:
void avoidLeak1() {
std::unique_ptr<int> ptr(new int);
// 作用域结束时,std::unique_ptr自动调用delete释放内存
}
- **工作原理**:`std::unique_ptr`采用独占所有权模式,它拥有指向对象的唯一指针。当`std::unique_ptr`对象销毁(例如离开作用域)时,其析构函数会自动调用`delete`释放所指向的内存,从而确保不会发生忘记释放内存的情况。对于数组,有`std::unique_ptr<int[]>`,其析构函数会调用`delete[]`。
2. std::shared_ptr
:
- 避免内存泄漏方式:
void avoidLeak2() {
std::shared_ptr<int> ptr(new int);
// 多个std::shared_ptr可指向同一对象,当最后一个指向对象的std::shared_ptr销毁时,内存被释放
}
- **工作原理**:`std::shared_ptr`采用引用计数的方式管理内存。多个`std::shared_ptr`可以指向同一个对象,每个`std::shared_ptr`内部维护一个引用计数。当一个`std::shared_ptr`对象创建时,引用计数加1;当一个`std::shared_ptr`对象销毁时,引用计数减1。当引用计数降为0时,表示没有任何`std::shared_ptr`指向该对象,此时自动调用`delete`释放内存,从而避免了异常抛出等情况下内存未释放的问题。
3. std::weak_ptr
(配合std::shared_ptr
):
- 避免内存泄漏方式:主要用于解决std::shared_ptr
的循环引用问题。例如:
class B;
class A {
public:
std::shared_ptr<B> ptrB;
};
class B {
public:
std::weak_ptr<A> ptrA; // 使用std::weak_ptr避免循环引用
};
- **工作原理**:`std::weak_ptr`不增加引用计数,它是对`std::shared_ptr`所管理对象的一种弱引用。当`std::shared_ptr`的引用计数为0并释放对象后,`std::weak_ptr`可以检测到所指向的对象已被释放,避免了因循环引用导致的内存泄漏。通过`lock()`方法,`std::weak_ptr`可以尝试获取一个`std::shared_ptr`,如果对象已被释放,`lock()`将返回一个空的`std::shared_ptr`。