面试题答案
一键面试智能指针优点
- 自动内存管理:
std::unique_ptr
、std::shared_ptr
能在对象不再被使用时自动释放其所管理的内存,避免了手动释放内存可能导致的内存泄漏问题。例如:
{
std::unique_ptr<int> uPtr(new int(10));
// 当uPtr离开其作用域时,指向的int对象内存会自动释放
}
- 异常安全:智能指针在异常抛出时也能正确释放内存,保证代码的异常安全性。例如:
void func() {
std::shared_ptr<int> sPtr(new int(20));
// 假设这里有代码可能抛出异常
// 无论异常是否发生,sPtr离开作用域时会释放内存
}
- 资源管理:
std::unique_ptr
可以用来管理非内存资源,如文件句柄等,确保资源在对象生命周期结束时被正确释放。
class FileRAII {
public:
FileRAII(const char* filename) : file(fopen(filename, "r")) {}
~FileRAII() { if (file) fclose(file); }
private:
FILE* file;
};
std::unique_ptr<FileRAII> filePtr(new FileRAII("test.txt"));
智能指针缺点
- 性能开销:
std::shared_ptr
由于使用引用计数,会有一定的性能开销,包括引用计数的增加、减少操作,以及可能的内存分配(用于控制块)。 - 代码复杂性:使用智能指针可能会增加代码的复杂性,尤其是涉及到
std::weak_ptr
来解决循环引用问题时,需要更多的代码逻辑和理解。例如:
class B;
class A {
public:
std::shared_ptr<B> bPtr;
};
class B {
public:
std::weak_ptr<A> aWeakPtr;
};
这里为了避免A和B之间的循环引用,B中使用 std::weak_ptr
指向A。
裸指针优点
- 简单直接:裸指针使用简单,在一些简单场景下,代码编写更加直观。例如:
int* num = new int(5);
// 使用num进行简单操作
delete num;
- 性能高效:没有智能指针的额外开销,在性能敏感的代码段,裸指针可能更高效。
裸指针缺点
- 内存管理风险:需要手动释放内存,容易出现忘记释放(内存泄漏)、多次释放(悬空指针)等问题。例如:
int* ptr = new int(10);
// 这里忘记delete ptr
- 缺乏资源管理:对于非内存资源,裸指针无法自动管理其生命周期。
何时选择智能指针
- 复杂对象管理:在涉及到对象的创建、传递和销毁的复杂场景,特别是在多线程环境下,智能指针能有效避免内存泄漏和悬空指针问题,如模块间传递对象时。
- 共享资源:当多个模块需要共享一个对象的所有权时,
std::shared_ptr
是很好的选择。例如:
class Data {
// 数据成员和成员函数
};
std::shared_ptr<Data> dataPtr(new Data());
// 将dataPtr传递给不同模块使用
- 自动资源释放:对于需要自动释放的资源,如文件句柄、网络连接等,
std::unique_ptr
能确保资源在对象生命周期结束时被正确释放。
何时选择裸指针
- 简单临时使用:在简单的局部变量,且生命周期易于管理的情况下,裸指针可以提供简单直接的操作。例如在一个函数内部简单地创建和使用一个临时对象。
- 性能关键代码:在性能敏感的代码段,如对时间要求苛刻的算法核心部分,裸指针可以避免智能指针的额外开销。
不同模块间指针类型转换和对象传递
- 裸指针转智能指针:
std::unique_ptr
:
int* rawPtr = new int(10);
std::unique_ptr<int> uPtr(rawPtr);
- **`std::shared_ptr`**:
int* rawPtr = new int(20);
std::shared_ptr<int> sPtr(rawPtr);
- 智能指针转裸指针:
std::unique_ptr
:
std::unique_ptr<int> uPtr(new int(30));
int* rawPtr = uPtr.get();
- **`std::shared_ptr`**:
std::shared_ptr<int> sPtr(new int(40));
int* rawPtr = sPtr.get();
- 跨模块传递:
- 使用
std::unique_ptr
传递:假设模块A创建对象并传递给模块B
- 使用
// 模块A
std::unique_ptr<SomeClass> createObject() {
return std::unique_ptr<SomeClass>(new SomeClass());
}
// 模块B
void useObject(std::unique_ptr<SomeClass> objPtr) {
// 使用objPtr
}
// 主函数
auto obj = createObject();
useObject(std::move(obj));
- **使用 `std::shared_ptr` 传递**:
// 模块A
std::shared_ptr<SomeClass> createSharedObject() {
return std::shared_ptr<SomeClass>(new SomeClass());
}
// 模块B
void useSharedObject(std::shared_ptr<SomeClass> objPtr) {
// 使用objPtr
}
// 主函数
auto sharedObj = createSharedObject();
useSharedObject(sharedObj);
通过以上方式,可以在不同模块间安全地进行指针类型的转换和对象传递,确保整个项目的内存安全和高效运行。