三、智能指针:自动管理动态内存,避免内存泄漏
痛点场景:
C++中用new动态分配内存后,必须用delete手动释放,否则会导致内存泄漏。实际开发中,很容易因忘记delete、异常导致delete未执行、或重复delete而崩溃。
什么是智能指针?
智能指针是封装了原始指针的类,它通过RAII(资源获取即初始化) 机制,在智能指针的生命周期结束时(如离开作用域),自动调用delete释放内存。
C++标准库提供了三种常用智能指针:std::unique_ptr、std::shared_ptr、std::weak_ptr。
1. std::unique_ptr:独占所有权
- 特性:一个对象只能被一个
unique_ptr拥有,所有权不可复制(只能移动)。 - 用途:管理“独占”的动态资源(如局部动态对象、类的成员对象)。
示例:避免手动delete
场景:管理类的成员资源
比如一个File类,需要管理文件指针(动态资源):
class File {
private:
// 用unique_ptr管理FILE*(需自定义删除器,因为FILE*用fclose释放)
std::unique_ptr<FILE, decltype(&fclose)> fp;
public:
File(const char* filename, const char* mode)
: fp(fopen(filename, mode), &fclose) { // 构造时打开文件
if (!fp) {
throw std::runtime_error("文件打开失败");
}
}
// 无需写析构函数!fp离开作用域时自动调用fclose关闭文件
};
int main() {
try {
File file("test.txt", "w"); // 打开文件
// 使用文件...
} catch (...) {
// 即使发生异常,file的fp也会自动关闭,不会泄漏文件句柄
}
return 0;
}
2. std::shared_ptr:共享所有权
- 特性:多个
shared_ptr可以共享同一个对象,内部通过“引用计数”记录所有者数量,当最后一个shared_ptr销毁时,才释放对象。 - 用途:管理“共享”的动态资源(如多个对象需要引用同一个资源)。
示例:多对象共享资源
// 共享的资源类
class Resource {
public:
Resource() { std::cout << "Resource创建\n"; }
~Resource() { std::cout << "Resource销毁\n"; }
};
void func1(std::shared_ptr<Resource> ptr) {
std::cout << "func1中引用计数:" << ptr.use_count() << "\n"; // 2
}
int main() {
// 创建shared_ptr,引用计数=1
std::shared_ptr<Resource> ptr = std::make_shared<Resource>();
std::cout << "main中引用计数:" << ptr.use_count() << "\n"; // 1
func1(ptr); // 传递给func1,引用计数=2(func1的ptr和main的ptr共享)
std::cout << "func1结束后引用计数:" << ptr.use_count() << "\n"; // 1
// main结束,ptr销毁,引用计数=0,Resource被自动销毁
return 0;
}
输出:
Resource创建
main中引用计数:1
func1中引用计数:2
func1结束后引用计数:1
Resource销毁
3. std::weak_ptr:解决shared_ptr的循环引用
- 痛点:如果两个
shared_ptr互相引用,会导致引用计数永远不为0,资源无法释放(循环引用泄漏)。 - 特性:
weak_ptr是shared_ptr的“弱引用”,不增加引用计数,可用于观察shared_ptr管理的对象,不影响其生命周期。
用weak_ptr解决:
class B;
class A {
public:
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A销毁\n"; }
};
class B {
public:
std::weak_ptr<A> a_ptr; // 用weak_ptr引用A,不增加计数
~B() { std::cout << "B销毁\n"; }
};
int main() {
{
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b; // b计数=2
b->a_ptr = a; // a计数仍为1(weak_ptr不增加计数)
}
// a离开作用域,计数减为0 → A销毁 → a->b_ptr销毁,b计数减为1
// b离开作用域,计数减为0 → B销毁
// 输出:A销毁 B销毁(无泄漏)
return 0;
}
智能指针的核心意义:
- 自动管理内存:避免手动
delete,从根源上减少内存泄漏。 - 安全:即使发生异常,也能保证资源释放(RAII机制)。
- 明确所有权:
unique_ptr(独占)和shared_ptr(共享)清晰表达资源的使用方式,代码更易理解。
总结:这些特性解决了什么问题?
| 特性 | 解决的痛点 | 核心价值 |
|---|---|---|
| 回调 | 组件无法预知未来要执行的逻辑 | 解耦组件与业务,提高灵活性 |
| std::function | 各种可调用对象接口不统一,难以管理 | 统一接口,简化可调用对象的存储和传递 |
| 智能指针 | 手动管理内存易泄漏、崩溃 | 自动释放资源,提高代码安全性和可维护性 |
理解它们的关键是:这些特性都是为了让代码更符合实际开发需求——更灵活、更安全、更少出错。在复杂项目中,不用这些特性会导致代码臃肿、易错,而用好它们能显著提升开发效率和代码质量。
浙公网安备 33010602011771号