智能指针是什么?
智能指针对已有 C++ 指针的封装,方便内存管理。一般有三种智能指针,但使用中主要分为两类场景:
unique_ptr:独占所有权,无法复制,只能 move()。
shared_ptr 和 weak_ptr:共享与弱引用配合使用。
shared_ptr:引用计数,多指针共享同一资源。
weak_ptr:弱引用,不增加引用计数,通过 lock() 安全访问对象。
基础使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include <iostream> #include <memory> #include <string> #include <windows.h>
using namespace std;
class A; class B; class C;
weak_ptr<A> global_weak_a; weak_ptr<B> global_weak_b; weak_ptr<C> global_weak_c;
class B { public: shared_ptr<A> aPtr; ~B() { cout << "B被销毁" << endl; } };
class A { public: shared_ptr<B> bPtr; shared_ptr<C> cPtr; ~A() { cout << "A被销毁" << endl; } };
class C { public: weak_ptr<A> aPtr; ~C() { cout << "C被销毁" << endl; } };
void UniquePtrExample(){ std::unique_ptr<std::string> strPtr = std::make_unique<std::string>("Hello, Smart Pointer!"); std::unique_ptr<std::string> strPtr2 = std::move(strPtr); if (strPtr == nullptr) { std::cout << "strPtr is now empty after ownership transfer." << std::endl; } else { std::cout << "strPtr is not empty: " << *strPtr << std::endl; } std::cout<<"strPtr2 is not empty: " << *strPtr2 << std::endl;
}
void circularReferenceExample() { std::cout << "---进入函数作用域---" << std::endl; auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); std::cout << "创建后 - A的引用计数: " << a.use_count() << std::endl; std::cout << "创建后 - C的引用计数: " << b.use_count() << std::endl;
a->bPtr = b; b->aPtr = a; std::cout << "设置互相引用后 - A的引用计数: " << a.use_count() << std::endl; std::cout << "设置互相引用后 - B的引用计数: " << b.use_count() << std::endl; std::cout << "---函数作用域即将结束---" << std::endl;
}
void break_circularReferenceExample() { auto a = make_shared<A>(); cout << "A的引用计数: " << a.use_count() << endl; auto c = make_shared<C>(); cout << "C的引用计数: " << c.use_count() << endl; global_weak_a = a; global_weak_c = c;
a->cPtr = c; cout << "设置 a->bPtr 后,c的引用计数: " << c.use_count() << endl; c->aPtr = a; cout << "设置 c->aPtr 后,A的引用计数: " << a.use_count() << endl; cout << "\n作用域结束前:" << endl; cout << "A的引用计数: " << a.use_count() << endl; cout << "C的引用计数: " << c.use_count() << endl; cout << "\n作用域结束后" << endl; }
int main() { SetConsoleOutputCP(65001);
cout << "开始测试循环引用..." << endl; break_circularReferenceExample(); cout << "\n程序结束" << endl; auto final_a = global_weak_a.lock(); auto final_b = global_weak_b.lock(); auto final_c = global_weak_c.lock(); cout << "\n检查对象状态..." << endl; cout << "\n程序结束时的状态:" << endl; cout << "A对象: " << (final_a ? "仍然存在" : "已被销毁") << endl; cout << "B对象: " << (final_b ? "仍然存在" : "已被销毁") << endl; cout << "C对象: " << (final_c ? "仍然存在" : "已被销毁") << endl; system("pause"); return 0; }
|
游戏应用
场景管理父子关系、容器与元素之间的关系:
1 2 3 4 5 6 7 8 9 10
| class Parent; class Child;
class Parent { shared_ptr<Child> child; };
class Child { weak_ptr<Parent> parent; };
|
多线程安全
面试问题smart ptr 安全吗?
| 操作对象 |
线程安全 |
原因 |
| 引用计数 |
安全 |
内部使用原子操作 |
| 所指的对象数据 |
不安全 |
多个线程同时修改同一块内存 |
| 指针本身的指向 |
不安全 |
赋值操作非原子(包含更新数据指针和控制块指针 |
| 特性 |
1. 所指对象数据不安全 |
2. 指针本身的指向不安全 |
| 打个比方 |
几个人同时在一间教室里乱搬桌子。 |
几个人在抢夺教室的钥匙,把钥匙掰断了。 |
| 受损处 |
教室里的桌椅(对象数据)。 |
钥匙和锁(shared_ptr 本身的 16 字节内存)。 |
| 解决工具 |
在对象内部加 std::mutex。 |
使用 std::atomic<shared_ptr> 或给 p1 加锁。 |
| 常见误区 |
以为引用计数是原子的,对象修改就安全。 |
以为 p1 只是一个指针(8字节),赋值是原子的。 |
https://www.cnblogs.com/KillerAery/p/9096558.html