C++智能指针 - 实践

C++智能指针学习

01.理解智能指针

#include <iostream>
  #include "MyObject.h"
  using namespace std;
  //
  void memory_leak_example(bool condition) {
  std::cout <<
  "\n--- Running Memory Leak Example ---" << std::endl;
  MyObject* ptr = new MyObject(1);
  // 在堆上创建对象
  /* 此处会出现内存泄露,即为 new 的指针不会被释放
  if (condition) {
  std::cout << "Condition is true, returning early..." << std::endl;
  // 如果在这里返回,下面的 delete 将永远不会被执行
  return;
  }*/
  ptr->
  pointer_example();
  delete ptr;
  // 只有当 condition 为 false 时,这里才会被执行
  std::cout <<
  "--- Memory Leak Example Finished ---\n" << std::endl;
  }
  int main() {
  // 场景 A: 发生内存泄漏
  memory_leak_example(true);
  std::cout <<
  "After memory_leak_example(true), the object was never destroyed." << std::endl;
  // 场景 B: 没有发生内存泄漏 (只是为了对比)
  memory_leak_example(false);
  return 0;
  }

02.unique_ptr

#include "MyObject.h"
#include <memory>
  // 必须包含这个头文件
  #include <vector>
    //智能指针无论从哪个路径退出,只要栈对象被销毁,自动释放内存
    void unique_ptr_basic_example(bool condition) {
    std::cout <<
    "\n--- Running unique_ptr Basic Example ---" << std::endl;
    // 推荐用法:使用 std::make_unique 创建对象并由 unique_ptr 管理
    // 这行代码做了两件事:1. new MyObject(3) 2. 创建一个 unique_ptr 指向它
    auto ptr = std::make_unique<MyObject >
      (3);
      if (condition) {
      std::cout <<
      "Condition is true, returning early..." << std::endl;
      // 当函数在这里返回时,ptr 会离开作用域
      // 它的析构函数会被自动调用,从而 delete 其管理的对象
      return;
      }
      ptr->
      do_something();
      std::cout <<
      "No need to manually call delete!" << std::endl;
      // 函数结束,ptr 离开作用域,自动 delete 对象
      }
      int main() {
      // 无论 condition 是 true 还是 false,内存都会被正确释放!
      unique_ptr_basic_example(true);
      unique_ptr_basic_example(false);
      return 0;
      }

03.所有权转移

#include <iostream>
  #include "MyObject.h"
  #include <vector>
    using namespace std;
    // 工厂函数,创建对象并返回其所有权
    std::unique_ptr<MyObject>
      create_object(int id) {
      std::cout <<
      "Factory creating an object..." << std::endl;
      return std::make_unique<MyObject>
        (id);
        // 返回时,所有权被自动移动(转移)出去,无需手动写 std::move
        }
        void unique_ptr_ownership_example() {
        std::cout <<
        "\n--- Running unique_ptr Ownership Example ---" << std::endl;
        // 1. 从工厂函数获取所有权
        auto ptr1 = create_object(4);
        // 2. 尝试复制(这是错误的!)
        // auto ptr2 = ptr1; // 这行代码会导致编译错误!
        std::cout <<
        "Cannot copy a unique_ptr." << std::endl;
        // 3. 转移所有权
        std::cout <<
        "Moving ownership from ptr1 to ptr2..." << std::endl;
        auto ptr2 = std::move(ptr1);
        // 使用 std::move 转移所有权
        // 检查所有权状态
        if (!ptr1) {
        std::cout <<
        "ptr1 is now nullptr." << std::endl;
        }
        std::cout <<
        "ptr2 now owns the object." << std::endl;
        ptr2->
        do_something();
        // 4. 将 unique_ptr 存入容器
        std::vector<std::unique_ptr<MyObject>> object_list;
          // 必须使用 move 将所有权转移给 vector
          object_list.push_back(std::move(ptr2));
          std::cout <<
          "Object moved into the vector." << std::endl;
          if (!ptr2) {
          std::cout <<
          "ptr2 is now nullptr after moving into vector." << std::endl;
          }
          // 当 main 函数结束时,object_list 会被销毁,
          // 它内部的所有 unique_ptr 也会被销毁,从而释放所有对象
          }
          int main() {
          unique_ptr_ownership_example();
          std::cout <<
          "\nEnd of main, all objects should be destroyed now." << std::endl;
          return 0;
          }

04_与函数交互 (获取裸指针)

#include <iostream>
  #include "MyObject.h"
  #include <vector>
    using namespace std;
    // 假设这是一个第三方库的函数,它只接受裸指针,并且不会尝试 delete 它
    void process_raw_pointer(MyObject* raw_ptr) {
    if (raw_ptr) {
    std::cout <<
    "Processing object via raw pointer..." << std::endl;
    raw_ptr->
    do_something();
    }
    delete raw_ptr;
    }
    void unique_ptr_raw_pointer_example() {
    std::cout <<
    "\n--- Running unique_ptr Raw Pointer Example ---" << std::endl;
    auto ptr = std::make_unique<MyObject>
      (5);
      // 使用 .get() 方法获取裸指针,但不要释放它!
      // 所有权仍然在 unique_ptr 手中
      process_raw_pointer(ptr.get());
      //.get() 提供了一个“只读”的、临时的裸指针
      std::cout <<
      "After processing, unique_ptr still owns the object." << std::endl;
      } // 函数结束,ptr 离开作用域,对象被安全销毁
      int main() {
      unique_ptr_raw_pointer_example();
      return 0;
      }

05.shared_ptr 的基本用法与引用计数

// main.cpp
#include <memory>
  #include <vector>
    #include <iostream>
      #include "MyObject.h"
      //shared_ptr 通过引用计数,精确地追踪有多少个指针在共享同一个对象。
      // 只有当最后一个 shared_ptr 被销毁时,对象才会被释放
      void shared_ptr_basic_example() {
      std::cout <<
      "\n--- Running shared_ptr Basic Example ---" << std::endl;
      // 推荐用法:使用 std::make_shared 创建对象
      auto s_ptr1 = std::make_shared<MyObject>
        (10);
        std::cout <<
        "s_ptr1 created. Use count: " << s_ptr1.use_count() << std::endl;
        // 输出: 1
        {
        // 创建一个新的作用域
        std::cout <<
        "Entering new scope..." << std::endl;
        // 复制 s_ptr1。这是 shared_ptr 的核心能力。
        std::shared_ptr<MyObject> s_ptr2 = s_ptr1;
          //不是同一个指针,但它们指向同一个对象
          std::cout <<
          "s_ptr2 created by copying s_ptr1. Use count: " << s_ptr1.use_count() << std::endl;
          // 输出: 2
          std::cout <<
          "s_ptr2 use count is also: " << s_ptr2.use_count() << std::endl;
          // 输出: 2
          s_ptr2->
          do_something();
          std::cout <<
          "Leaving new scope..." << std::endl;
          } // s_ptr2 在这里离开作用域,被销毁,引用计数减 1
          std::cout <<
          "After scope, s_ptr2 is destroyed. Use count: " << s_ptr1.use_count() << std::endl;
          // 输出: 1
          std::cout <<
          "--- shared_ptr Basic Example Finished ---\n" << std::endl;
          //-----------
          std::cout <<
          "Entering new scope..." << std::endl;
          // 复制 s_ptr1。这是 shared_ptr 的核心能力。
          std::shared_ptr<MyObject> s_ptr2 = s_ptr1;
            std::cout <<
            "!!!s_ptr2 created by copying s_ptr1. Use count: " << s_ptr1.use_count() << std::endl;
            // 输出: 2
            std::cout <<
            "!!!s_ptr2 use count is also: " << s_ptr2.use_count() << std::endl;
            // 输出: 2
            s_ptr2->
            do_something();
            std::cout <<
            "Leaving new scope..." << std::endl;
            } // main 函数结束前,s_ptr1 在这里被销毁,引用计数变为 0,对象被 delete
            int main() {
            shared_ptr_basic_example();
            return 0;
            }

06_shared_ptr 与容器和函数

// main.cpp
#include <memory>
  #include <vector>
    #include <iostream>
      #include "MyObject.h"
      // 一个函数,接收一个 shared_ptr,表示它将临时共享该对象的所有权
      void process_shared_object(std::shared_ptr<MyObject> ptr) {
        std::cout <<
        " [Inside function] Received object. Use count: " << ptr.use_count() << std::endl;
        //3
        ptr->
        do_something();
        std::cout <<
        " [Inside function] Function finished." << std::endl;
        } // 函数结束,参数 ptr 被销毁,引用计数减 1
        void shared_ptr_advanced_example() {
        std::cout <<
        "\n--- Running shared_ptr Advanced Example ---" << std::endl;
        std::vector<std::shared_ptr<MyObject>> object_list;
          // 1. 创建对象并存入 vector
          auto s_ptr = std::make_shared<MyObject>
            (11);
            std::cout <<
            "Object created. Use count: " << s_ptr.use_count() << std::endl;
            // 1
            object_list.push_back(s_ptr);
            //复制操作,但是指向同一个shared_ptr
            std::cout <<
            "Object pushed into vector. Use count: " << s_ptr.use_count() << std::endl;
            // 2 (s_ptr 和 vector中的元素)
            // 2. 将 s_ptr 传递给函数
            std::cout <<
            "Calling function..." << std::endl;
            process_shared_object(s_ptr);
            std::cout <<
            "Function returned. Use count: " << s_ptr.use_count() << std::endl;
            // 2 (s_ptr 和 vector中的元素)
            // 3. 释放我们本地的 s_ptr
            s_ptr.reset();
            // 主动放弃所有权,只有s_ptr这一个指针放弃,其实就是s_ptr=nullptr
            std::cout <<
            "s_ptr reset. Use count: " << object_list[0].use_count() << std::endl;
            // 1 (只剩下 vector 中的元素)
            std::cout <<
            "--- shared_ptr Advanced Example Finished ---\n" << std::endl;
            } // main 函数结束前,vector 被销毁,它内部的 shared_ptr 也被销毁,引用计数变为 0,对象被 delete
            int main() {
            shared_ptr_advanced_example();
            return 0;
            }

07_weak_ptr循环引用导致的内存泄漏

// main.cpp
#include <memory>
  #include <vector>
    #include <iostream>
      #include "MyObject.h"
      // 定义两个相互引用的类
      class Son;
      // 前向声明
      class Father {
      public:
      Father() { std::cout <<
      "Father created." << std::endl;
      }
      ~Father() { std::cout <<
      "Father destroyed." << std::endl;
      }
      std::shared_ptr<Son> son_;
        };
        class Son {
        public:
        Son() { std::cout <<
        "Son created." << std::endl;
        }
        ~Son() { std::cout <<
        "Son destroyed." << std::endl;
        }
        std::shared_ptr<Father> father_;
          };
          void circular_reference_problem() {
          std::cout <<
          "\n--- Running Circular Reference Problem ---" << std::endl;
          auto father = std::make_shared<Father>
            ();
            // Father use_count = 1
            auto son = std::make_shared<Son>
              ();
              // Son use_count = 1
              // 建立相互引用,两者只是来回引用,并没有无限套娃
              father->son_ = son;
              // Son use_count = 2
              son->father_ = father;
              // Father use_count = 2
              std::cout <<
              "Father use count: " << father.use_count() << std::endl;
              std::cout <<
              "Son use count: " << son.use_count() << std::endl;
              std::cout <<
              "Leaving function scope..." << std::endl;
              } // 函数结束,father 和 son 两个局部智能指针被销毁
              // Father use_count 减为 1 (因为 Son 还指着它)
              // Son use_count 减为 1 (因为 Father 还指着它)
              // 引用计数都无法归零,析构函数永远不会被调用!
              int main() {
              circular_reference_problem();
              std::cout <<
              "After function, objects were NOT destroyed. Memory leak!" << std::endl;
              return 0;
              }

08_weak_ptr 打破循环引用

// main.cpp
#include <memory>
  #include <vector>
    #include <iostream>
      #include "MyObject.h"
      // 只需要修改 Son 的定义
      class SonFixed;
      class FatherFixed {
      public:
      FatherFixed() { std::cout <<
      "FatherFixed created." << std::endl;
      }
      ~FatherFixed() { std::cout <<
      "FatherFixed destroyed." << std::endl;
      }
      std::shared_ptr<SonFixed> son_;
        };
        class SonFixed {
        public:
        SonFixed() { std::cout <<
        "SonFixed created." << std::endl;
        }
        ~SonFixed() { std::cout <<
        "SonFixed destroyed." << std::endl;
        }
        // 关键改动:使用 weak_ptr
        // Son 只是“观察” Father,不拥有他
        std::weak_ptr<FatherFixed> father_;
          };
          void circular_reference_solution() {
          std::cout <<
          "\n--- Running Circular Reference Solution ---" << std::endl;
          auto father = std::make_shared<FatherFixed>
            ();
            // Father use_count = 1
            auto son = std::make_shared<SonFixed>
              ();
              // Son use_count = 1
              father->son_ = son;
              // Son use_count = 2
              son->father_ = father;
              // Father use_count 仍然是 1,因为 weak_ptr 不增加计数!
              std::cout <<
              "Father use count: " << father.use_count() << std::endl;
              std::cout <<
              "Son use count: " << son.use_count() << std::endl;
              // 如何通过 weak_ptr 访问对象?
              if (!son->father_.expired()) {
              // 1. 检查对象是否还存在
              // 2. 使用 lock() 获取一个临时的 shared_ptr
              std::shared_ptr<FatherFixed> father_sptr = son->father_.lock();
                if (father_sptr) {
                std::cout <<
                "Son can access Father. Father use count temporarily becomes: " << father_sptr.use_count() << std::endl;
                }
                } // father_sptr 在此被销毁,引用计数恢复
                std::cout <<
                "Leaving function scope..." << std::endl;
                } // 函数结束,father 和 son 局部指针被销毁
                // father 的 use_count 减为 0 -> FatherFixed 被销毁
                // FatherFixed 的析构函数被调用,其成员 son_ (一个shared_ptr)被销毁
                // son 的 use_count 减为 0 -> SonFixed 被销毁
                int main() {
                circular_reference_solution();
                std::cout <<
                "After function, objects were correctly destroyed." << std::endl;
                return 0;
                }

09_使用 unique_ptr 管理 FILE

#include <cstdio>
  #include <memory>
    #include <iostream>
      // 自定义删除器,一个简单的函数
      void file_closer(FILE* file) {
      if (file) {
      std::cout <<
      "Custom deleter: Closing file." << std::endl;
      fclose(file);
      }
      }
      // 使用函数指针作为删除器类型
      using FileUniquePtr = std::unique_ptr<FILE, decltype(&file_closer)>
      ;
      void unique_ptr_deleter_example() {
      std::cout <<
      "\n--- unique_ptr Custom Deleter Example ---" << std::endl;
      // 打开文件,获取 C 风格的句柄
      FILE* raw_file_ptr = fopen("test.txt", "w");
      if (!raw_file_ptr) return;
      // 创建 unique_ptr,并提供删除器
      // 注意构造函数需要传入原始指针和删除器函数指针
      FileUniquePtr file_ptr(raw_file_ptr, &file_closer);
      fprintf(file_ptr.get(), "Hello from unique_ptr with a custom deleter!\n");
      std::cout <<
      "Function scope is ending, file will be closed automatically." << std::endl;
      } // file_ptr 在此被销毁,它会自动调用 file_closer(raw_file_ptr)
      int main() {
      unique_ptr_deleter_example();
      return 0;
      }

10shared_ptr 和 Lambda 实现自定义删除器

#include <memory>
  #include <iostream>
    struct ThirdPartyResource {
    ThirdPartyResource(int id) : id_(id) { std::cout <<
    "Resource " << id_ <<
    " acquired." << std::endl;
    }
    int id_;
    };
    // 假设这是一个第三方C库的释放函数
    void release_third_party_resource(ThirdPartyResource* res) {
    std::cout <<
    "Custom C-style release function called for resource " << res->id_ <<
      "." << std::endl;
      delete res;
      // 假设它内部也是用 delete
      }
      void shared_ptr_deleter_example() {
      std::cout <<
      "\n--- shared_ptr Custom Deleter Example ---" << std::endl;
      // 创建 shared_ptr,并将自定义删除器作为第二个参数传入
      // 使用 lambda 表达式非常方便
      std::shared_ptr<ThirdPartyResource>
        res_ptr(
        new ThirdPartyResource(101),
        [](ThirdPartyResource* r) {
        std::cout <<
        "Custom lambda deleter called for resource " << r->id_ <<
          "." << std::endl;
          delete r;
          }
          );
          // 也可以传递一个函数指针
          std::shared_ptr<ThirdPartyResource>
            res_ptr2(new ThirdPartyResource(102), &release_third_party_resource);
            std::cout <<
            "Function scope is ending, resources will be released." << std::endl;
            }
            int main() {
            shared_ptr_deleter_example();
            return 0;
            }

11_this 指针共享

#include <memory>
  #include <iostream>
    #include <vector>
      // 必须公开继承自 std::enable_shared_from_this
      class GameObject : public std::enable_shared_from_this<GameObject>
        {
        public:
        GameObject() { std::cout <<
        "GameObject created." << std::endl;
        }
        ~GameObject() { std::cout <<
        "GameObject destroyed." << std::endl;
        }
        // 这个方法需要返回一个指向自身的 shared_ptr
        std::shared_ptr<GameObject>
          get_shared_ptr() {
          // 错误的做法: return std::shared_ptr<GameObject>(this);
            // 正确的做法:
            return shared_from_this();
            }
            void add_to_manager() {
            // 假设一个游戏管理器需要存储对这个对象的共享引用
            get_game_manager().push_back(get_shared_ptr());
            }
            private:
            // 模拟一个全局的游戏管理器
            static std::vector<std::shared_ptr<GameObject>>
              &
              get_game_manager() {
              static std::vector<std::shared_ptr<GameObject>> manager;
                return manager;
                }
                };
                void enable_shared_from_this_example() {
                std::cout <<
                "\n--- enable_shared_from_this Example ---" << std::endl;
                // 重要:要使用 shared_from_this,对象必须首先被一个 shared_ptr 管理
                auto obj1 = std::make_shared<GameObject>
                  ();
                  // 让对象自己把自己注册到管理器中
                  obj1->
                  add_to_manager();
                  std::cout <<
                  "After registration, obj1 use count: " << obj1.use_count() << std::endl;
                  // 尝试在没有被 shared_ptr 管理的情况下调用
                  GameObject raw_obj;
                  try {
                  // 这会抛出一个 std::bad_weak_ptr 异常
                  // raw_obj.get_shared_ptr();
                  }
                  catch (const std::bad_weak_ptr& e) {
                  std::cout <<
                  "Caught expected exception: " << e.what() << std::endl;
                  }
                  std::cout <<
                  "Function scope is ending..." << std::endl;
                  }
                  int main() {
                  enable_shared_from_this_example();
                  // main 结束后,全局的 manager 才被销毁,最终 GameObject 被释放
                  return 0;
                  }

12shared_ptr 和 Lambda 实现自定义删除器

#include <memory>
  #include <iostream>
    struct ThirdPartyResource {
    ThirdPartyResource(int id) : id_(id) { std::cout <<
    "Resource " << id_ <<
    " acquired." << std::endl;
    }
    int id_;
    };
    // 假设这是一个第三方C库的释放函数
    void release_third_party_resource(ThirdPartyResource* res) {
    std::cout <<
    "Custom C-style release function called for resource " << res->id_ <<
      "." << std::endl;
      delete res;
      // 假设它内部也是用 delete
      }
      void shared_ptr_deleter_example() {
      std::cout <<
      "\n--- shared_ptr Custom Deleter Example ---" << std::endl;
      // 创建 shared_ptr,并将自定义删除器作为第二个参数传入
      // 使用 lambda 表达式非常方便
      std::shared_ptr<ThirdPartyResource>
        res_ptr(
        new ThirdPartyResource(101),
        [](ThirdPartyResource* r) {
        std::cout <<
        "Custom lambda deleter called for resource " << r->id_ <<
          "." << std::endl;
          delete r;
          }
          );
          // 也可以传递一个函数指针
          std::shared_ptr<ThirdPartyResource>
            res_ptr2(new ThirdPartyResource(102), &release_third_party_resource);
            std::cout <<
            "Function scope is ending, resources will be released." << std::endl;
            }
            int main() {
            shared_ptr_deleter_example();
            return 0;
            }
posted @ 2025-09-07 10:40  wzzkaifa  阅读(10)  评论(0)    收藏  举报