1make_sharedmake_shared的基本用法一起完成申请内存初始化对象绑定shared_ptr举例子就像你想和同学共享一本书分两步做方式一newshared_ptr先去书店买一本书new申请内存再单独买一个 “借书登记本”shared_ptr内部的引用计数最后把书和登记本绑定在一起。问题如果买完书、还没买登记本时你突然有事走了比如程序中间出异常—— 书就丢了内存泄漏方式二std::make_shared就像你去书店一次性把 “书 借书登记本” 买好老板直接帮你绑定在一起一步到位申请书的内存 申请登记本的内存 绑定绝对安全不会出现 “书买了但登记本没买” 的情况。1. 基本用法创建简单类型比如int、string语法std::make_shared类型(初始值)#include iostream #include memory // 必须包含这个头文件 int main() { // 推荐写法用 make_shared 创建 shared_ptr指向存了 10 的 int std::shared_ptrint p1 std::make_sharedint(10); // 等价于但不推荐先 new 再绑定 shared_ptr // std::shared_ptrint p1(new int(10)); // 像普通指针一样用 std::cout *p1 std::endl; // 输出 10 return 0; }2. 创建类对象结合 ROS2 场景语法std::make_shared类名(构造函数参数)#include iostream #include memory #include string // 定义一个简单的 Person 类 class Person { public: std::string name; // 构造函数需要传入名字 Person(std::string n) : name(n) {} void say_hello() { std::cout Hello, Im name std::endl; } }; int main() { // 用 make_shared 创建 Person 对象传入构造函数参数 张三 std::shared_ptrPerson p std::make_sharedPerson(张三); // 用 - 访问类成员 p-say_hello(); // 输出 Hello, Im 张三 return 0; }2shared_ptr一、先搞懂为什么需要shared_ptr在讲shared_ptr之前先看普通指针的两个坑坑 1忘记delete导致内存泄漏// 普通指针写法 void test() { int* p new int(10); // 从堆区申请内存存了个10 // ... 业务逻辑 // 忘记写 delete p; —— 内存泄漏这块内存永远不会被释放 }就像你从图书馆借了一本书看完忘了还 —— 书内存就一直被你占着别人用不了时间久了图书馆系统就没书内存可用了。坑 2重复delete导致程序崩溃// 普通指针写法 void test() { int* p1 new int(10); int* p2 p1; // p2 和 p1 指向同一块内存 delete p1; // 释放内存 // ... 业务逻辑 delete p2; // 重复释放同一块内存程序直接崩溃 }就像你和同学都借了同一本书你先还了同学又去还一次 —— 图书馆管理员系统直接懵了程序就崩了。普通指针的问题是内存的 “申请” 和 “释放” 全靠人手动管人总会忘事、犯错 —— 而shared_ptr就是来帮你自动管内存的不用你写delete也不会重复释放。二、用生活类比秒懂shared_ptr原理shared_ptr的核心逻辑可以用「共享一本书」的例子解释你、小明、小红三个人共享一本《C 入门》书买回来时申请内存只有你在看 ——「当前看书人数」 1小明也想看你把书借给他 ——「当前看书人数」 2小红也加入 ——「当前看书人数」 3你看完了不看了 ——「当前看书人数」 2小明也看完了 ——「当前看书人数」 1小红最后看完 ——「当前看书人数」 0关键当没人看了人数 0书就被收起来释放内存。对应到shared_ptr原理shared_ptr内部有一个 **「引用计数」**就像上面的「当前看书人数」每多一个shared_ptr指向同一块内存引用计数 1每销毁一个shared_ptr比如超出作用域、被重置引用计数 -1当引用计数 0 时shared_ptr自动释放内存不用你写delete。shared_ptr两大作用自动管理内存引用计数原理释放内存共享所有权能读取同一个地方的值1. 创建shared_ptr用std::make_shared这是创建shared_ptr最安全、最常用的方式类比「去书店买一本新书」#include iostream #include memory // 必须包含这个头文件才能用 shared_ptr int main() { // 创建一个 shared_ptr指向一个存了 10 的 int 类型内存 // std::make_shared类型(初始值) —— 推荐写法 std::shared_ptrint p1 std::make_sharedint(10); // 等价于 ROS2 里的写法ROS2 封装了别名但本质一样 // rclcpp::Publisherstd_msgs::msg::String::SharedPtr publisher_; // 本质就是std::shared_ptrrclcpp::Publisher... publisher_; // 用 *p1 访问内存里的值像普通指针一样 std::cout *p1 std::endl; // 输出 10 return 0; } // 程序结束p1 超出作用域引用计数0自动释放内存2. 复制shared_ptr引用计数 1类比「把书借给同学看」复制后两个shared_ptr指向同一块内存#include iostream #include memory int main() { std::shared_ptrint p1 std::make_sharedint(10); std::cout p1 的引用计数 p1.use_count() std::endl; // 输出 1 // 复制 p1 给 p2 —— 引用计数 1 std::shared_ptrint p2 p1; std::cout p1 的引用计数 p1.use_count() std::endl; // 输出 2 std::cout p2 的引用计数 p2.use_count() std::endl; // 输出 2同一块内存计数共享 // *p1 和 *p2 访问的是同一块内存 *p2 20; std::cout *p1 std::endl; // 输出 20p1 的值也变了 return 0; } // p1 和 p2 都超出作用域引用计数从 2 减到 0自动释放内存3. 重置shared_ptr引用计数 -1类比「你看完书不看了」重置后shared_ptr不再指向原来的内存#include iostream #include memory int main() { std::shared_ptrint p1 std::make_sharedint(10); std::shared_ptrint p2 p1; // 引用计数 2 // 重置 p1 —— p1 不再指向原来的内存引用计数 -1变成 1 p1.reset(); std::cout p2 的引用计数 p2.use_count() std::endl; // 输出 1 // 重置 p2 —— 引用计数 -1变成 0自动释放内存 p2.reset(); return 0; }4. 像普通指针一样用shared_ptr*和-shared_ptr只是 “包装” 了普通指针用法完全一样#include iostream #include memory #include string // 定义一个简单的类 class Person { public: std::string name; Person(std::string n) : name(n) {} void say_hello() { std::cout Hello, Im name std::endl; } }; int main() { // 创建 shared_ptr指向 Person 对象 std::shared_ptrPerson p std::make_sharedPerson(张三); // 用 - 访问对象的成员和普通指针一样 p-say_hello(); // 输出 Hello, Im 张三 // 用 * 访问对象本身 (*p).name 李四; p-say_hello(); // 输出 Hello, Im 李四 return 0; }