C++智能指针学习
01.理解智能指针
c
复制代码
#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
c
复制代码
#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.所有权转移
c
复制代码
#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_与函数交互 (获取裸指针)
c
复制代码
#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 的基本用法与引用计数
c
复制代码
// 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 与容器和函数
c
复制代码
// 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循环引用导致的内存泄漏
c
复制代码
// 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 打破循环引用
c
复制代码
// 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
c
复制代码
#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 实现自定义删除器
c
复制代码
#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 指针共享
c
复制代码
#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 实现自定义删除器
c
复制代码
#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;
}