基础能力
看智能指针,需要你先学会指针!
【C++指针完全解读】新手也能玩转的“内存地图“导航手册-CSDN博客
🎈 一、智能指针是什么?
想象你养了一只电子宠物(内存对象),每次忘记喂食(释放内存)它就会饿死(内存泄漏)。智能指针就像自动喂食器,帮你记住何时该清理内存!
传统指针的痛点:
int* pet = new int(5); // 领养宠物
// ...中间可能忘记写 delete...
// 宠物饿死了 QAQ
智能指针救星:
#include <memory>
auto smart_pet = std::make_unique<int>(5);
// 不用手动delete!离开作用域自动清理
🧩 二、三大智能指针详解
1. unique_ptr:专属管家
特点:
-
唯一主人(不能复制)
-
轻量高效(接近裸指针)
-
离开作用域自动释放
代码全解:
// 创建方式(C++14推荐make_unique)
auto cat = std::make_unique<std::string>("Tom");
// 转移所有权(原指针变空)
auto new_owner = std::move(cat);
// 错误示例:
// auto copy = cat; // 编译报错!禁止复制
// 手动释放(一般不需要!)
new_owner.reset(); // 等同于delete操作
2. shared_ptr:共享家庭
特点:
-
多人共享(引用计数)
-
计数为0时自动清理
-
稍重(维护计数开销)
代码全解:
// 创建方式(优先用make_shared)
auto dog = std::make_shared<std::string>("Bobby");
// 复制增加计数
auto family_member1 = dog; // 计数+1 → 2
{
auto family_member2 = dog; // 计数+1 → 3
} // 成员2离开,计数-1 → 2
// 查看当前计数(调试用)
std::cout << dog.use_count(); // 输出2
// 手动释放(不推荐!)
dog.reset(); // 计数-1 → 1(若计数为0才释放内存)
3. weak_ptr:安全观察员
特点:
-
不增加引用计数
-
解决循环引用问题
-
必须通过lock()获取临时使用权
代码全解:
// 创建方式(从shared_ptr转换)
auto rabbit = std::make_shared<int>(10);
std::weak_ptr<int> weak_rabbit = rabbit;
// 尝试访问(安全!)
if (auto temp = weak_rabbit.lock()) {
std::cout << *temp; // 访问成功
} else {
std::cout << "对象已销毁";
}
// 典型应用场景:打破循环引用
struct Node {
// std::shared_ptr<Node> parent; // ❌ 循环引用
std::weak_ptr<Node> parent; // ✅ 正确方式
};
🚨 三、避坑大作战
坑1:混合使用原始指针
int* raw = new int(20);
std::shared_ptr<int> sp1(raw); // 正确
// std::shared_ptr<int> sp2(raw); // 灾难!重复释放
✅ 正确做法:
auto sp1 = std::make_shared<int>(20); // 从开始就用智能指针
坑2:返回智能指针的裸指针
auto sp = std::make_shared<int>(30);
int* dangerous = sp.get();
delete dangerous; // 导致双重释放!
✅ 牢记:.get()
获得的指针只能观察,不能delete!
坑3:循环引用
struct A {
std::shared_ptr<B> b_ptr;
};
struct B {
std::shared_ptr<A> a_ptr; // 互相持有→内存泄漏!
};
✅ 解决方案:
struct B {
std::weak_ptr<A> a_ptr; // 改用weak_ptr
};
🗺️ 四、选择指针的决策图
是否需要共享对象? ├── 否 → 用unique_ptr(默认首选) └── 是 → 是否可能循环引用? ├── 否 → 用shared_ptr └── 是 → 组合使用shared_ptr + weak_ptr
💡 五、性能小贴士
-
优先用make_xxx:
// 更好:单次内存分配(对象+控制块) auto sp = std::make_shared<MyClass>(args); // 较差:两次分配(可能引发内存碎片) std::shared_ptr<MyClass> sp(new MyClass(args));
-
避免大量shared_ptr拷贝:
void process(const std::shared_ptr<Object>& obj); // 传引用避免计数操作
unique_ptr性能几乎无损耗:可放心替代裸指针!
🌈 结语:
智能指针不是魔法,但能让你的代码:
✅ 减少80%内存相关bug
✅ 更易读和维护
✅ 安全地拥抱C++的强大能力