C++学习系列(11):智能指针(unique_ptr、shared_ptr、weak_ptr)
1. 引言
在 C++ 传统的内存管理方式中,动态分配的对象需要手动释放,否则可能会导致 内存泄漏(Memory Leak)。为了解决这个问题,C++11 引入了 智能指针(Smart Pointer),它能 自动管理资源,避免内存泄漏。
本篇博客将介绍:
- 智能指针的概念
- 三种智能指针:
unique_ptr、shared_ptr、weak_ptr - 智能指针的使用技巧
- 如何避免智能指针的错误用法
2. 智能指针概述
智能指针是一个 包装类,用于管理动态分配的对象,并在 不再需要对象时自动释放内存。
C++ 提供了三种智能指针:
| 智能指针 | 特点 | 适用场景 |
|---|---|---|
unique_ptr | 独占所有权,不能共享 | 适用于 唯一所有权 |
shared_ptr | 共享所有权,使用 引用计数 | 适用于 多个对象共享同一资源 |
weak_ptr | 弱引用,不影响引用计数 | 适用于 避免循环引用 |
3. unique_ptr(独占所有权)
3.1 unique_ptr 的基本用法
#include <iostream>
#include <memory>
class Foo {
public:
Foo() { std::cout << "Foo 构造\n"; }
~Foo() { std::cout << "Foo 析构\n"; }
void show() { std::cout << "Hello from Foo\n"; }
};
int main() {
std::unique_ptr<Foo> ptr = std::make_unique<Foo>(); // 创建 unique_ptr
ptr->show(); // 访问对象成员
return 0; // 离开作用域时,Foo 自动销毁
}
📌 解析
std::unique_ptr<Foo> ptr = std::make_unique<Foo>();✅ 推荐使用make_uniqueunique_ptr不能被复制,只能 移动。
3.2 unique_ptr 不能复制
std::unique_ptr<Foo> ptr1 = std::make_unique<Foo>();
std::unique_ptr<Foo> ptr2 = ptr1; // ❌ 错误:不能复制
3.3 unique_ptr 的所有权转移
std::unique_ptr<Foo> ptr1 = std::make_unique<Foo>();
std::unique_ptr<Foo> ptr2 = std::move(ptr1); // ✅ 允许移动
4. shared_ptr(共享所有权)
4.1 shared_ptr 的基本用法
#include <iostream>
#include <memory>
class Foo {
public:
Foo() { std::cout << "Foo 构造\n"; }
~Foo() { std::cout << "Foo 析构\n"; }
};
int main() {
std::shared_ptr<Foo> ptr1 = std::make_shared<Foo>();
std::shared_ptr<Foo> ptr2 = ptr1; // 共享同一对象
std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 2
return 0; // 当最后一个 shared_ptr 离开作用域时,Foo 被销毁
}
📌 解析
std::make_shared<Foo>()✅ 推荐使用make_sharedshared_ptr可以被多个指针共享。- 通过
use_count()查看当前引用计数。
4.2 shared_ptr 的引用计数
std::shared_ptr<int> sp1 = std::make_shared<int>(100);
std::shared_ptr<int> sp2 = sp1; // sp1 和 sp2 共享对象
std::cout << sp1.use_count() << std::endl; // 输出 2
5. weak_ptr(弱引用)
5.1 weak_ptr 的基本用法
#include <iostream>
#include <memory>
class Foo {
public:
Foo() { std::cout << "Foo 构造\n"; }
~Foo() { std::cout << "Foo 析构\n"; }
};
int main() {
std::shared_ptr<Foo> sp = std::make_shared<Foo>();
std::weak_ptr<Foo> wp = sp; // 创建 weak_ptr
std::cout << "引用计数: " << sp.use_count() << std::endl; // 1
if (auto locked = wp.lock()) { // 转换为 shared_ptr
std::cout << "对象仍然存在\n";
}
return 0;
}
📌 解析
weak_ptr不会影响引用计数- 需要
lock()转换为shared_ptr才能访问对象 - 适用于 避免
shared_ptr循环引用。
5.2 避免 shared_ptr 循环引用
#include <iostream>
#include <memory>
class B;
class A {
public:
std::shared_ptr<B> bptr;
~A() { std::cout << "A 析构\n"; }
};
class B {
public:
std::weak_ptr<A> aptr; // 解决循环引用
~B() { std::cout << "B 析构\n"; }
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->bptr = b;
b->aptr = a; // 解决循环引用
return 0;
}
📌 解析
weak_ptr不会增加引用计数,避免了shared_ptr循环引用导致的内存泄漏。
6. 智能指针对比
| 智能指针 | 所有权 | 引用计数 | 是否可以共享 | 适用场景 |
|---|---|---|---|---|
unique_ptr | 独占 | 无 | ❌ | 单个对象,唯一所有权 |
shared_ptr | 共享 | 有 | ✅ | 多个对象共享同一资源 |
weak_ptr | 弱引用 | 无 | ✅(但不影响计数) | 避免 shared_ptr 循环引用 |
7. 总结
✅ unique_ptr 适用于 独占资源,不可复制,但可移动
✅ shared_ptr 适用于 共享资源,引用计数自动管理
✅ weak_ptr 适用于 避免 shared_ptr 循环引用
📢 下一篇 C++学习系列(12):C++ 线程与多线程编程,敬请期待!🚀
💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!
3万+

被折叠的 条评论
为什么被折叠?



