[C++面试] RAII资源获取即初始化(重点)-CSDN博客
[C++面试] 智能指针面试点(重点)-CSDN博客
unique_ptr:可通过特化删除器管理数组,需显式指定delete[]
std::unique_ptr arr(new int[5]{1,2,3,4,5});
shared_ptr:默认使用delete
而非delete[]
,直接管理数组会导致未定义行为。需自定义删除器
std::shared_ptr arr(new int[5], [](int* p) { delete[] p; });
std::vector> vec;
vec.push_back(std::make_shared(42));
std::vector> vec1 = {std::make_shared(42)};
auto vec2 = vec1; // 引用计数变为2
std::vector> vec3 = {std::make_unique(42)};
auto vec4 = std::move(vec3); // vec3变为空
auto_ptr
被废弃std::auto_ptr p1(new int(5));
std::auto_ptr p2 = p1; // p1变为空指针
std::cout << *p1; // 运行时崩溃
std::make_shared
和std::make_unique
的额外优势delete
释放对象,无法处理非堆内存(如文件句柄)。// 自定义删除器释放文件句柄
std::shared_ptr file(fopen("test.txt", "r"), [](FILE* f) { fclose(f); });
会被正确释放。智能指针利用 RAII 机制,在离开作用域时(包括异常场景)自动释放资源,避免内存泄漏。
void test() {
auto ptr = std::make_shared(42);
throw std::runtime_error("Exception!"); // ptr会被正确释放
}
悬空指针:若原始指针指向的对象被智能指针释放,后续使用原始指针会导致未定义行为
int* raw = new int(10);
std::shared_ptr sp(raw);
delete raw; // sp变为悬空指针
重复释放:多个智能指针管理同一原始指针(如p2(raw))会导致重复释放。
场景:父子节点互相持有shared_ptr
导致引用计数永不为零。
解决方案:将其中一个指针改为weak_ptr,如树形结构的父节点用weak_ptr,子节点用shared_ptr
class Node {
public:
std::shared_ptr child;
std::weak_ptr parent; // 打破循环
};
使用std::dynamic_pointer_cast
进行安全的向下转型
class Base {};
class Derived : public Base {};
// 创建子类实体,赋值给基类指针
std::shared_ptr base = std::make_shared();
// 指向子类实体的基类指针,还原回子类
std::shared_ptr derived = std::dynamic_pointer_cast(base);
if (derived) { /* 安全使用 */ }
dynamic_pointer_cast 的安全转型,必须用于 shared_ptr 之间的转型
std::shared_ptr base = std::make_shared();
if (auto derived = std::dynamic_pointer_cast(base)) {
// 安全使用
}
使用
static_pointer_cast
、dynamic_pointer_cast
进行类型转换,保留引用计数
std::atomic
)或互斥锁保护引用计数。std::shared_ptr
保证引用计数操作的原子性,但对象访问仍需额外同步。std::make_shared
减少内存分配次数。一次分配控制块和对象内存,减少内存碎片,提升缓存利用率shared_from_this()
吗?不能,因对象尚未被shared_ptr
管理,引发std::bad_weak_ptr
异常
正确用法:仅在对象已被shared_ptr管理后调用,如在成员函数中。
class Worker : public std::enable_shared_from_this {
public:
void start() {
auto self = shared_from_this(); // 安全
}
// 构造函数中调用会导致异常!
};
1、为什么 unique_ptr 只能通过std::move
转移所有权?
std::move
显式转移所有权,避免隐式错误。2、智能指针类型选择
工厂模式用 unique_ptr,缓存用 shared_ptr
3、通过get()
获取裸指针后,若其生命周期长于shared_ptr
,会导致悬空指针
std::shared_ptr sp = std::make_shared(42);
int* raw = sp.get();
sp.reset(); // raw成为悬空指针
4、误用weak_ptr:未检查lock()结果直接使用,引发访问已释放对象。