c++内存 | 内存泄露 | 共享指针
github热门推荐 › c++内存 | 内存泄露 | 共享指针 (第 80 章)
一、什么是内存泄漏
1.1 概念图解
┌─────────────────────────────────────────────────────────────────┐│ 内存泄漏示意图 │├─────────────────────────────────────────────────────────────────┤│ ││ 程序开始 运行中 程序结束 ││ ↓ ↓ ↓ ││ ┌──────┐ ┌──────┐ ┌──────┐ ││ │ 堆 │ │ 堆 │ │ 堆 │ ││ │ 空 │ ──────► │ ████ │ ◄── 泄漏 │ ████ │ ◄── 无法释放││ └──────┘ │ ████ │ │ ████ │ ││ └──────┘ └──────┘ ││ ││ 分配内存 ✓ 使用内存 ✓ 释放内存 ✗ ││ │└─────────────────────────────────────────────────────────────────┘
1.2 指针重新赋值导致的内存泄漏
<span leaf=""><span class="code-snippet__comment">// 文件:memory_leak_demo.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cstdlib></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">pointer_reassign_leak</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__comment">// 错误示例:指针重新赋值导致内存泄漏</span></span></code><code><span leaf=""> <span class="code-snippet__type">char</span> *p = (<span class="code-snippet__type">char</span> *)<span class="code-snippet__built_in">malloc</span>(<span class="code-snippet__number">10</span>);</span></code><code><span leaf=""> <span class="code-snippet__type">char</span> *p1 = (<span class="code-snippet__type">char</span> *)<span class="code-snippet__built_in">malloc</span>(<span class="code-snippet__number">10</span>);</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 假设 p 指向地址 0x1000,p1 指向地址 0x2000</span></span></code><code><span leaf=""> p = p1; <span class="code-snippet__comment">// ❌ p 原来指向的 0x1000 丢失了!内存泄漏!</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 正确做法:先释放再赋值</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// free(p);</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// p = p1;</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">/*</span></span></code><code><span leaf="">┌─────────┐ 分配前 分配后 重新赋值后</span></code><code><span leaf="">│ │ ┌─────┐ ┌─────┐</span></code><code><span leaf="">│ p │ ─────────► 0x1000│ 10B │ p ──►│ 10B │ (0x2000)</span></code><code><span leaf="">│ │ └─────┘ └─────┘</span></code><code><span leaf="">│ p1 │ ─────────► 0x2000┌─────┐ p1 ──►┌─────┐</span></code><code><span leaf="">│ │ │ 10B │ │ 10B │ (0x2000)</span></code><code><span leaf="">└─────────┘ └─────┘ └─────┘</span></code><code><span leaf=""> ┌─────┐</span></code><code><span leaf=""> 遗留 │ 10B │ ← 无法访问!</span></code><code><span leaf=""> └─────┘</span></code><code><span leaf="">*/</span>1.3 常见内存泄漏场景
<span leaf=""><span class="code-snippet__comment">// 文件:common_leaks.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cstring></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 场景1:忘记释放</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">forget_release</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">100</span>);</span></code><code><span leaf=""> <span class="code-snippet__comment">// 使用 p...</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 忘记 delete p;</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 场景2:异常导致无法释放</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">exception_leak</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__type">int</span>[<span class="code-snippet__number">1000</span>];</span></code><code><span leaf=""> <span class="code-snippet__comment">// 如果这里抛出异常,delete 永远不会执行</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">throw</span> <span class="code-snippet__built_in">runtime_error</span>(<span class="code-snippet__string">"something wrong"</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span>[] p; <span class="code-snippet__comment">// ❌ 永远不会执行</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 场景3:循环引用(后面详细讲)</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Node</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> shared_ptr<Node> next;</span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Node</span>() { cout << <span class="code-snippet__string">"Node destroyed"</span> << endl; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">cycle_ref_leak</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Node> </span><span class="code-snippet__function"><span class="code-snippet__title">n1</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Node())</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Node> </span><span class="code-snippet__function"><span class="code-snippet__title">n2</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Node())</span></span>;</span></code><code><span leaf=""> n1->next = n2;</span></code><code><span leaf=""> n2->next = n1; <span class="code-snippet__comment">// ❌ 循环引用,两个都不会被释放</span></span></code><code><span leaf="">}</span>二、防止内存泄漏的方法
2.1 RAII封装(构造时获取,析构时释放)
<span leaf=""><span class="code-snippet__comment">// 文件:raii_wrapper.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cstring></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 基础版本:有浅拷贝问题</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">SimpleRAII</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">private</span>:</span></code><code><span leaf=""> <span class="code-snippet__type">char</span>* p;</span></code><code><span leaf=""> <span class="code-snippet__type">unsigned</span> <span class="code-snippet__type">int</span> p_size;</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__built_in">SimpleRAII</span>(<span class="code-snippet__type">unsigned</span> <span class="code-snippet__type">int</span> n = <span class="code-snippet__number">1</span>) {</span></code><code><span leaf=""> p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__type">char</span>[n];</span></code><code><span leaf=""> p_size = n;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"构造:分配内存"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">SimpleRAII</span>() {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (p != <span class="code-snippet__literal">NULL</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span>[] p;</span></code><code><span leaf=""> p = <span class="code-snippet__literal">NULL</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"析构:释放内存"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">char</span></span><span class="code-snippet__function">* </span><span class="code-snippet__function"><span class="code-snippet__title">GetPointer</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> p; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 浅拷贝问题演示</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">shallow_copy_problem</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__function">SimpleRAII </span><span class="code-snippet__function"><span class="code-snippet__title">ex</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">100</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">)</span></span>;</span></code><code><span leaf=""> SimpleRAII ex1 = ex; <span class="code-snippet__comment">// ❌ 浅拷贝!两个对象指向同一内存</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// 析构时会释放两次 → 程序崩溃</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__comment">// 运行结果:构造:分配内存</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 析构:释放内存</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 析构:释放内存 ← 崩溃!</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== 正确版本:使用引用计数 ====================</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">RefCountRAII</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">private</span>:</span></code><code><span leaf=""> <span class="code-snippet__type">char</span>* p;</span></code><code><span leaf=""> <span class="code-snippet__type">unsigned</span> <span class="code-snippet__type">int</span> p_size;</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p_count; <span class="code-snippet__comment">// 引用计数指针</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__built_in">RefCountRAII</span>(<span class="code-snippet__type">unsigned</span> <span class="code-snippet__type">int</span> n = <span class="code-snippet__number">1</span>) {</span></code><code><span leaf=""> p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__type">char</span>[n];</span></code><code><span leaf=""> p_size = n;</span></code><code><span leaf=""> p_count = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">1</span>);</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"构造:分配内存,count = "</span> << *p_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 拷贝构造:引用计数+1</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">RefCountRAII</span>(<span class="code-snippet__type">const</span> RefCountRAII& temp) {</span></code><code><span leaf=""> p = temp.p;</span></code><code><span leaf=""> p_size = temp.p_size;</span></code><code><span leaf=""> p_count = temp.p_count;</span></code><code><span leaf=""> (*p_count)++;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"拷贝构造:count = "</span> << *p_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 赋值运算符</span></span></code><code><span leaf=""> RefCountRAII& <span class="code-snippet__keyword">operator</span>=(<span class="code-snippet__type">const</span> RefCountRAII& temp) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__keyword">this</span> != &temp) {</span></code><code><span leaf=""> <span class="code-snippet__comment">// 先减少当前对象的引用计数</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (--(*p_count) == <span class="code-snippet__number">0</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span>[] p;</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> p_count;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"释放旧内存"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__comment">// 指向新对象</span></span></code><code><span leaf=""> p = temp.p;</span></code><code><span leaf=""> p_size = temp.p_size;</span></code><code><span leaf=""> p_count = temp.p_count;</span></code><code><span leaf=""> (*p_count)++;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"赋值操作:count = "</span> << *p_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> *<span class="code-snippet__keyword">this</span>;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">RefCountRAII</span>() {</span></code><code><span leaf=""> (*p_count)--;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"析构:count = "</span> << *p_count << endl;</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (*p_count == <span class="code-snippet__number">0</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span>[] p;</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> p_count;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"释放内存 ✓"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">char</span></span><span class="code-snippet__function">* </span><span class="code-snippet__function"><span class="code-snippet__title">GetPointer</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> p; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 测试引用计数版本</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">test_ref_count</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n=== 测试引用计数RAII ==="</span> << endl;</span></code><code><span leaf=""> <span class="code-snippet__function">RefCountRAII </span><span class="code-snippet__function"><span class="code-snippet__title">ex</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">100</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">)</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__built_in">strcpy</span>(ex.<span class="code-snippet__built_in">GetPointer</span>(), <span class="code-snippet__string">"Test"</span>);</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"ex.p = "</span> << ex.<span class="code-snippet__built_in">GetPointer</span>() << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> RefCountRAII ex1 = ex; <span class="code-snippet__comment">// 拷贝构造,计数+1</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"ex1.p = "</span> << ex<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">GetPointer</span>() << endl;</span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__comment">// 输出:</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 构造:分配内存,count = 1</span></span></code><code><span leaf=""><span class="code-snippet__comment">// ex.p = Test</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 拷贝构造:count = 2</span></span></code><code><span leaf=""><span class="code-snippet__comment">// ex1.p = Test</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 析构:count = 1</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 析构:count = 0</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 释放内存 ✓</span></span>三、智能指针详解
3.1 三种智能指针对比图
┌─────────────────────────────────────────────────────────────────────┐│ C++11 智能指针家族 │├─────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ shared_ptr │ ││ │ ┌─────┐ ┌─────────────┐ ┌─────────┐ │ ││ │ │ ptr1│───►│ 控制块 │ │ 对象 │ │ ││ │ └─────┘ │ 引用计数: 2 │◄───┤ │ │ ││ │ ┌─────┐ │ 弱计数: 0 │ └─────────┘ │ ││ │ │ ptr2│───►└─────────────┘ │ ││ │ └─────┘ │ ││ │ 特点:多个指针共享所有权,引用计数归零时释放 │ ││ └─────────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ unique_ptr │ ││ │ ┌─────┐ ┌─────────┐ │ ││ │ │ ptr │────────►│ 对象 │ │ ││ │ └─────┘ └─────────┘ │ ││ │ 特点:独占所有权,不能拷贝,只能移动 │ ││ └─────────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ weak_ptr │ ││ │ ┌─────┐ ┌─────────────┐ ┌─────────┐ │ ││ │ │ wptr│───►│ 控制块 │ │ 对象 │ │ ││ │ └─────┘ │ 引用计数: 1 │◄───┤ │ │ ││ │ │ 弱计数: 1 │ └─────────┘ │ ││ │ └─────────────┘ │ ││ │ 特点:弱引用,不增加引用计数,用于打破循环引用 │ ││ └─────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────┘
3.2 智能指针完整实现(参考源码)
<span leaf=""><span class="code-snippet__comment">// 文件:smart_ptr_implementation.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cassert></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">template</span><<span class="code-snippet__keyword">typename</span> T></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">SharedPtr</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">private</span>:</span></code><code><span leaf=""> T* _ptr;</span></code><code><span leaf=""> <span class="code-snippet__type">size_t</span>* _count; <span class="code-snippet__comment">// 引用计数</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__comment">// 构造函数</span></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__keyword">explicit</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">SharedPtr</span></span><span class="code-snippet__function"><span class="code-snippet__params">(T* ptr = </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__literal">nullptr</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">)</span></span><span class="code-snippet__function"> : _ptr(ptr) {</span></span></code><code><span leaf=""> _count = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">size_t</span>(ptr ? <span class="code-snippet__number">1</span> : <span class="code-snippet__number">0</span>);</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"SharedPtr构造,引用计数 = "</span> << *_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 拷贝构造函数</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">SharedPtr</span>(<span class="code-snippet__type">const</span> SharedPtr<T>& other) {</span></code><code><span leaf=""> _ptr = other._ptr;</span></code><code><span leaf=""> _count = other._count;</span></code><code><span leaf=""> (*_count)++;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"SharedPtr拷贝构造,引用计数 = "</span> << *_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 赋值运算符</span></span></code><code><span leaf=""> SharedPtr<T>& <span class="code-snippet__keyword">operator</span>=(<span class="code-snippet__type">const</span> SharedPtr<T>& other) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__keyword">this</span> != &other) {</span></code><code><span leaf=""> <span class="code-snippet__comment">// 释放当前资源</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">release</span>();</span></code><code><span leaf=""> <span class="code-snippet__comment">// 接管新资源</span></span></code><code><span leaf=""> _ptr = other._ptr;</span></code><code><span leaf=""> _count = other._count;</span></code><code><span leaf=""> (*_count)++;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"SharedPtr赋值,引用计数 = "</span> << *_count << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> *<span class="code-snippet__keyword">this</span>;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 移动构造函数</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">SharedPtr</span>(SharedPtr<T>&& other) <span class="code-snippet__keyword">noexcept</span> {</span></code><code><span leaf=""> _ptr = other._ptr;</span></code><code><span leaf=""> _count = other._count;</span></code><code><span leaf=""> other._ptr = <span class="code-snippet__literal">nullptr</span>;</span></code><code><span leaf=""> other._count = <span class="code-snippet__literal">nullptr</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"SharedPtr移动构造"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 析构函数</span></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">SharedPtr</span>() {</span></code><code><span leaf=""> <span class="code-snippet__built_in">release</span>();</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">release</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (_count) {</span></code><code><span leaf=""> (*_count)--;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"SharedPtr析构,引用计数 = "</span> << *_count << endl;</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (*_count == <span class="code-snippet__number">0</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> _ptr;</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> _count;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"释放内存 ✓"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> T& <span class="code-snippet__keyword">operator</span>*() <span class="code-snippet__type">const</span> {</span></code><code><span leaf=""> <span class="code-snippet__built_in">assert</span>(_ptr != <span class="code-snippet__literal">nullptr</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> *_ptr;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> T* <span class="code-snippet__keyword">operator</span>->() <span class="code-snippet__type">const</span> {</span></code><code><span leaf=""> <span class="code-snippet__built_in">assert</span>(_ptr != <span class="code-snippet__literal">nullptr</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> _ptr;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function">T* </span><span class="code-snippet__function"><span class="code-snippet__title">get</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__type">const</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> _ptr; }</span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">size_t</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">use_count</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__type">const</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> _count ? *_count : <span class="code-snippet__number">0</span>; }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">bool</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">unique</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__type">const</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> <span class="code-snippet__built_in">use_count</span>() == <span class="code-snippet__number">1</span>; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 测试自定义SharedPtr</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Test</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__type">int</span> value;</span></code><code><span leaf=""> <span class="code-snippet__built_in">Test</span>(<span class="code-snippet__type">int</span> v = <span class="code-snippet__number">0</span>) : <span class="code-snippet__built_in">value</span>(v) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"Test对象构造: "</span> << value << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Test</span>() {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"Test对象析构: "</span> << value << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">test_custom_shared_ptr</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== 测试自定义SharedPtr ====="</span> << endl;</span></code><code><span leaf=""> <span class="code-snippet__function">SharedPtr<Test> </span><span class="code-snippet__function"><span class="code-snippet__title">sp1</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Test(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">100</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">))</span></span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp1.use_count() = "</span> << sp<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> {</span></code><code><span leaf=""> SharedPtr<Test> sp2 = sp1; <span class="code-snippet__comment">// 拷贝构造</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp2.use_count() = "</span> << sp<span class="code-snippet__number">2.</span><span class="code-snippet__built_in">use_count</span>() << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp1->value = "</span> << sp1->value << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"(*sp2).value = "</span> << (*sp2).value << endl;</span></code><code><span leaf=""> } <span class="code-snippet__comment">// sp2析构,引用计数减1</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp1.use_count() = "</span> << sp<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl;</span></code><code><span leaf="">} <span class="code-snippet__comment">// sp1析构,引用计数变0,释放内存</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== UniquePtr实现 ====================</span></span></code><code><span leaf=""><span class="code-snippet__keyword">template</span><<span class="code-snippet__keyword">typename</span> T></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">UniquePtr</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">private</span>:</span></code><code><span leaf=""> T* _ptr;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__keyword">explicit</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">UniquePtr</span></span><span class="code-snippet__function"><span class="code-snippet__params">(T* ptr = </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__literal">nullptr</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">)</span></span><span class="code-snippet__function"> : _ptr(ptr) {</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"UniquePtr构造"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 禁止拷贝</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">UniquePtr</span>(<span class="code-snippet__type">const</span> UniquePtr<T>&) = <span class="code-snippet__keyword">delete</span>;</span></code><code><span leaf=""> UniquePtr<T>& <span class="code-snippet__keyword">operator</span>=(<span class="code-snippet__type">const</span> UniquePtr<T>&) = <span class="code-snippet__keyword">delete</span>;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 允许移动</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">UniquePtr</span>(UniquePtr<T>&& other) <span class="code-snippet__keyword">noexcept</span> : _ptr(other._ptr) {</span></code><code><span leaf=""> other._ptr = <span class="code-snippet__literal">nullptr</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"UniquePtr移动构造"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> UniquePtr<T>& <span class="code-snippet__keyword">operator</span>=(UniquePtr<T>&& other) <span class="code-snippet__keyword">noexcept</span> {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__keyword">this</span> != &other) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> _ptr;</span></code><code><span leaf=""> _ptr = other._ptr;</span></code><code><span leaf=""> other._ptr = <span class="code-snippet__literal">nullptr</span>;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"UniquePtr移动赋值"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> *<span class="code-snippet__keyword">this</span>;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">UniquePtr</span>() {</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> _ptr;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"UniquePtr析构,释放内存"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> T& <span class="code-snippet__keyword">operator</span>*() <span class="code-snippet__type">const</span> { <span class="code-snippet__keyword">return</span> *_ptr; }</span></code><code><span leaf=""> T* <span class="code-snippet__keyword">operator</span>->() <span class="code-snippet__type">const</span> { <span class="code-snippet__keyword">return</span> _ptr; }</span></code><code><span leaf=""> <span class="code-snippet__function">T* </span><span class="code-snippet__function"><span class="code-snippet__title">get</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__type">const</span></span><span class="code-snippet__function"> </span>{ <span class="code-snippet__keyword">return</span> _ptr; }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function">T* </span><span class="code-snippet__function"><span class="code-snippet__title">release</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> T* tmp = _ptr;</span></code><code><span leaf=""> _ptr = <span class="code-snippet__literal">nullptr</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> tmp;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">reset</span></span><span class="code-snippet__function"><span class="code-snippet__params">(T* ptr = </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__literal">nullptr</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">)</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> _ptr;</span></code><code><span leaf=""> _ptr = ptr;</span></code><code><span leaf=""> }</span></code><code><span leaf="">};</span>3.3 智能指针使用示例
<span leaf=""><span class="code-snippet__comment">// 文件:smart_ptr_usage.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><memory></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><vector></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== shared_ptr 使用 ====================</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">shared_ptr_demo</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== shared_ptr 演示 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 创建 shared_ptr</span></span></code><code><span leaf=""> shared_ptr<<span class="code-snippet__type">int</span>> sp1 = <span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">42</span>);</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<</span><span class="code-snippet__function"><span class="code-snippet__type">int</span></span><span class="code-snippet__function">> </span><span class="code-snippet__function"><span class="code-snippet__title">sp2</span></span><span class="code-snippet__function"><span class="code-snippet__params">(sp1)</span></span>; <span class="code-snippet__comment">// 拷贝构造,引用计数+1</span></span></code><code><span leaf=""> shared_ptr<<span class="code-snippet__type">int</span>> sp3 = sp1; <span class="code-snippet__comment">// 赋值,引用计数+1</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp1 use_count: "</span> << sp<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 3</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp2 use_count: "</span> << sp<span class="code-snippet__number">2.</span><span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 3</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"*sp1 = "</span> << *sp1 << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> sp<span class="code-snippet__number">2.</span><span class="code-snippet__built_in">reset</span>(); <span class="code-snippet__comment">// 释放sp2,引用计数-1</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"after reset sp2, use_count: "</span> << sp<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 2</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== unique_ptr 使用 ====================</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">unique_ptr_demo</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== unique_ptr 演示 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function">unique_ptr<</span><span class="code-snippet__function"><span class="code-snippet__type">int</span></span><span class="code-snippet__function">> </span><span class="code-snippet__function"><span class="code-snippet__title">up1</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__type">int</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">100</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">))</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// unique_ptr<int> up2 = up1; // ❌ 编译错误,不能拷贝</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> unique_ptr<<span class="code-snippet__type">int</span>> up2 = <span class="code-snippet__built_in">move</span>(up1); <span class="code-snippet__comment">// ✓ 移动语义,所有权转移</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (up1 == <span class="code-snippet__literal">nullptr</span>) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"up1 现在是空指针"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"*up2 = "</span> << *up2 << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 工厂模式常用</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> make_resource = []() {</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> <span class="code-snippet__built_in">make_unique</span><string>(<span class="code-snippet__string">"Hello World"</span>);</span></code><code><span leaf=""> };</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> unique_ptr<string> up3 = <span class="code-snippet__built_in">make_resource</span>();</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"*up3 = "</span> << *up3 << endl;</span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== weak_ptr 使用 ====================</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">weak_ptr_demo</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== weak_ptr 演示 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> shared_ptr<<span class="code-snippet__type">int</span>> sp = <span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">999</span>);</span></code><code><span leaf=""> weak_ptr<<span class="code-snippet__type">int</span>> wp = sp; <span class="code-snippet__comment">// 弱引用,不增加引用计数</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"sp use_count: "</span> << sp.<span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 1</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"wp expired: "</span> << wp.<span class="code-snippet__built_in">expired</span>() << endl; <span class="code-snippet__comment">// false</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 使用 weak_ptr 前需要 lock() 转换为 shared_ptr</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__keyword">auto</span> locked = wp.<span class="code-snippet__built_in">lock</span>()) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"通过 weak_ptr 访问: "</span> << *locked << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> sp.<span class="code-snippet__built_in">reset</span>(); <span class="code-snippet__comment">// 释放共享指针</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"after reset, wp expired: "</span> << wp.<span class="code-snippet__built_in">expired</span>() << endl; <span class="code-snippet__comment">// true</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (wp.<span class="code-snippet__built_in">lock</span>() == <span class="code-snippet__literal">nullptr</span>) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"weak_ptr 指向的对象已被销毁"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== 循环引用问题与解决 ====================</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Child</span>; <span class="code-snippet__comment">// 前向声明</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Parent</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> shared_ptr<Child> child_ptr;</span></code><code><span leaf=""> <span class="code-snippet__comment">// weak_ptr<Child> child_ptr; // ✅ 解决方案:改用 weak_ptr</span></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Parent</span>() { cout << <span class="code-snippet__string">"Parent 析构"</span> << endl; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Child</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> shared_ptr<Parent> parent_ptr;</span></code><code><span leaf=""> <span class="code-snippet__comment">// weak_ptr<Parent> parent_ptr; // ✅ 解决方案</span></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Child</span>() { cout << <span class="code-snippet__string">"Child 析构"</span> << endl; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">cycle_reference_problem</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== 循环引用问题 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Parent> </span><span class="code-snippet__function"><span class="code-snippet__title">parent</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Parent())</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Child> </span><span class="code-snippet__function"><span class="code-snippet__title">child</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Child())</span></span>;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> parent->child_ptr = child; <span class="code-snippet__comment">// Parent 持有 Child</span></span></code><code><span leaf=""> child->parent_ptr = parent; <span class="code-snippet__comment">// Child 持有 Parent</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 引用计数都是2,离开作用域时都只减到1,永远不会为0</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// 导致内存泄漏!两个对象的析构函数都不会被调用</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">cycle_reference_fixed</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== 使用 weak_ptr 解决循环引用 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">ParentFixed</span> {</span></code><code><span leaf=""> <span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> weak_ptr<Child> child_ptr; <span class="code-snippet__comment">// ✅ 使用 weak_ptr</span></span></code><code><span leaf=""> ~<span class="code-snippet__built_in">ParentFixed</span>() { cout << <span class="code-snippet__string">"ParentFixed 析构"</span> << endl; }</span></code><code><span leaf=""> };</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">ChildFixed</span> {</span></code><code><span leaf=""> <span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> shared_ptr<ParentFixed> parent_ptr;</span></code><code><span leaf=""> ~<span class="code-snippet__built_in">ChildFixed</span>() { cout << <span class="code-snippet__string">"ChildFixed 析构"</span> << endl; }</span></code><code><span leaf=""> };</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<ParentFixed> </span><span class="code-snippet__function"><span class="code-snippet__title">parent</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> ParentFixed())</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<ChildFixed> </span><span class="code-snippet__function"><span class="code-snippet__title">child</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> ChildFixed())</span></span>;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> parent->child_ptr = child;</span></code><code><span leaf=""> child->parent_ptr = parent;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"parent use_count: "</span> << parent.<span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 1</span></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"child use_count: "</span> << child.<span class="code-snippet__built_in">use_count</span>() << endl; <span class="code-snippet__comment">// 2 (因为 Child 用 shared_ptr 持有 Parent)</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// 实际上最好两边都用 weak_ptr,根据实际业务需求决定</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// ==================== 最佳实践:使用 make_shared ====================</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">best_practices</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== 最佳实践 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 推荐:使用 make_shared(一次分配,更高效)</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> sp1 = <span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">42</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> sp2 = <span class="code-snippet__built_in">make_shared</span><string>(<span class="code-snippet__string">"Hello"</span>);</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 自定义删除器</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> file_deleter = [](FILE* f) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (f) {</span></code><code><span leaf=""> <span class="code-snippet__built_in">fclose</span>(f);</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"文件已关闭"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> };</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 管理C风格文件指针</span></span></code><code><span leaf=""> <span class="code-snippet__function">unique_ptr<FILE, </span><span class="code-snippet__function"><span class="code-snippet__title">decltype</span></span><span class="code-snippet__function"><span class="code-snippet__params">(file_deleter)</span></span><span class="code-snippet__function">> </span><span class="code-snippet__function"><span class="code-snippet__title">file_ptr</span></span><span class="code-snippet__function"><span class="code-snippet__params">(fopen(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__string">"test.txt"</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">, </span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__string">"w"</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">), file_deleter)</span></span>;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 不推荐:直接使用 new(可能造成异常安全问题)</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// shared_ptr<int> sp3(new int(10)); // 可能导致内存泄漏</span></span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 使用 vector 存储智能指针</span></span></code><code><span leaf=""> vector<shared_ptr<<span class="code-snippet__type">int</span>>> vec;</span></code><code><span leaf=""> vec.<span class="code-snippet__built_in">push_back</span>(<span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">1</span>));</span></code><code><span leaf=""> vec.<span class="code-snippet__built_in">push_back</span>(<span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">2</span>));</span></code><code><span leaf=""> vec.<span class="code-snippet__built_in">push_back</span>(<span class="code-snippet__built_in">make_shared</span><<span class="code-snippet__type">int</span>>(<span class="code-snippet__number">3</span>));</span></code><code><span leaf="">}</span>3.4 unique_ptr 移动赋值详解
<span leaf=""><span class="code-snippet__comment">// 文件:unique_ptr_move.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><memory></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Resource</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__type">int</span> id;</span></code><code><span leaf=""> <span class="code-snippet__built_in">Resource</span>(<span class="code-snippet__type">int</span> i) : <span class="code-snippet__built_in">id</span>(i) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"Resource "</span> << id << <span class="code-snippet__string">" 创建"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Resource</span>() {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"Resource "</span> << id << <span class="code-snippet__string">" 销毁"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf="">};</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">unique_ptr_move_demo</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n===== unique_ptr 移动赋值详解 ====="</span> << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 创建两个 unique_ptr</span></span></code><code><span leaf=""> <span class="code-snippet__function">unique_ptr<Resource> </span><span class="code-snippet__function"><span class="code-snippet__title">up1</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Resource(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">1</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">))</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__function">unique_ptr<Resource> </span><span class="code-snippet__function"><span class="code-snippet__title">up2</span></span><span class="code-snippet__function"><span class="code-snippet__params">(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__keyword">new</span></span></span><span class="code-snippet__function"><span class="code-snippet__params"> Resource(</span></span><span class="code-snippet__function"><span class="code-snippet__params"><span class="code-snippet__number">2</span></span></span><span class="code-snippet__function"><span class="code-snippet__params">))</span></span>;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"up1 指向 Resource "</span> << up1->id << endl;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"up2 指向 Resource "</span> << up2->id << endl;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> <span class="code-snippet__comment">// 转移所有权:up1 的所有权转移给 up2</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// 原来的 up2 指向的资源会被释放</span></span></code><code><span leaf=""> up2 = <span class="code-snippet__built_in">move</span>(up1);</span></code><code><span leaf=""><br /></span></code><code><span leaf=""> cout << <span class="code-snippet__string">"n=== 移动后 ==="</span> << endl;</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (up1 == <span class="code-snippet__literal">nullptr</span>) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"up1 现在是空指针"</span> << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (up2 != <span class="code-snippet__literal">nullptr</span>) {</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"up2 现在指向 Resource "</span> << up2->id << endl;</span></code><code><span leaf=""> }</span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__comment">/*</span></span></code><code><span leaf="">输出:</span></code><code><span leaf="">Resource 1 创建</span></code><code><span leaf="">Resource 2 创建</span></code><code><span leaf="">up1 指向 Resource 1</span></code><code><span leaf="">up2 指向 Resource 2</span></code><code><span leaf="">Resource 2 销毁 ← up2 原来的资源被释放</span></code><code><span leaf="">=== 移动后 ===</span></code><code><span leaf="">up1 现在是空指针</span></code><code><span leaf="">up2 现在指向 Resource 1</span></code><code><span leaf="">Resource 1 销毁 ← 程序结束时释放</span></code><code><span leaf="">*/</span>3.5 共享指针避坑
<span leaf=""><span class="code-snippet__comment">// C++ 智能指针 核心坑点 + 注意事项(浓缩可直接运行参考)</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><memory></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><span class="code-snippet__comment">// 辅助测试类</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Test</span> {</span></code><code><span leaf=""><span class="code-snippet__keyword">public</span>:</span></code><code><span leaf=""> <span class="code-snippet__built_in">Test</span>() { cout << <span class="code-snippet__string">"Test 构造n"</span>; }</span></code><code><span leaf=""> ~<span class="code-snippet__built_in">Test</span>() { cout << <span class="code-snippet__string">"Test 析构n"</span>; }</span></code><code><span leaf=""> <span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">show</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{ cout << <span class="code-snippet__string">"Test::show()n"</span>; }</span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// 辅助函数:错误示范:不要返回局部对象的 unique_ptr</span></span></code><code><span leaf=""><span class="code-snippet__comment">// unique_ptr<Test> bad_return_local() {</span></span></code><code><span leaf=""><span class="code-snippet__comment">// Test t;</span></span></code><code><span leaf=""><span class="code-snippet__comment">// return make_unique<Test>(&t); // 野指针!</span></span></code><code><span leaf=""><span class="code-snippet__comment">// }</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">int</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">main</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 1. unique_ptr 核心坑 ====================</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 正确:make_unique 初始化</span></span></code><code><span leaf=""> unique_ptr<Test> u1 = <span class="code-snippet__built_in">make_unique</span><Test>();</span></code><code><span leaf=""> u1-><span class="code-snippet__built_in">show</span>();</span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 错误:不能拷贝,只能移动</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// unique_ptr<Test> u2 = u1; // 编译报错</span></span></code><code><span leaf=""> unique_ptr<Test> u2 = <span class="code-snippet__built_in">move</span>(u1); <span class="code-snippet__comment">// ✅ 必须 move</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (!u1) cout << <span class="code-snippet__string">"u1 已失效,所有权转移n"</span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 错误:同一裸指针构造多个 unique_ptr → 双重释放</span></span></code><code><span leaf=""> Test* p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">Test</span>();</span></code><code><span leaf=""> <span class="code-snippet__function">unique_ptr<Test> </span><span class="code-snippet__function"><span class="code-snippet__title">u3</span></span><span class="code-snippet__function"><span class="code-snippet__params">(p)</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// unique_ptr<Test> u4(p); // 崩溃!同一块内存被两个智能指针管理</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 2. shared_ptr 核心坑 ====================</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 正确:make_shared(推荐,效率高、安全)</span></span></code><code><span leaf=""> shared_ptr<Test> s1 = <span class="code-snippet__built_in">make_shared</span><Test>();</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"引用计数:"</span> << s<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl;</span></code><code><span leaf=""> shared_ptr<Test> s2 = s1;</span></code><code><span leaf=""> cout << <span class="code-snippet__string">"引用计数:"</span> << s<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">use_count</span>() << endl;</span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 错误:用裸指针初始化多个 shared_ptr → 双重释放</span></span></code><code><span leaf=""> Test* p2 = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">Test</span>();</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Test> </span><span class="code-snippet__function"><span class="code-snippet__title">s3</span></span><span class="code-snippet__function"><span class="code-snippet__params">(p2)</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// shared_ptr<Test> s4(p2); // 崩溃!两个独立控制块</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 致命坑:循环引用 → 内存泄漏</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">struct</span> <span class="code-snippet__title">Node</span> { shared_ptr<Node> next; };</span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> node1 = <span class="code-snippet__built_in">make_shared</span><Node>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">auto</span> node2 = <span class="code-snippet__built_in">make_shared</span><Node>();</span></code><code><span leaf=""> node1->next = node2;</span></code><code><span leaf=""> node2->next = node1;</span></code><code><span leaf=""> <span class="code-snippet__comment">// 出作用域不会析构!必须用 weak_ptr 打破循环</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 3. weak_ptr 核心坑 ====================</span></span></code><code><span leaf=""> weak_ptr<Test> w1 = s1;</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (!w<span class="code-snippet__number">1.</span><span class="code-snippet__built_in">expired</span>()) {</span></code><code><span leaf=""> shared_ptr<Test> tmp = w<span class="code-snippet__number">1.l</span>ock(); <span class="code-snippet__comment">// ✅ 必须 lock 才能访问</span></span></code><code><span leaf=""> tmp-><span class="code-snippet__built_in">show</span>();</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 错误:直接使用 weak_ptr 访问对象 → 编译报错</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// w1->show();</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 4. 通用致命坑 ====================</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 不要管理栈内存 → 重复释放崩溃</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// Test stack_obj;</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// shared_ptr<Test> s_bad(&stack_obj);</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 不要 delete 智能指针管理的裸指针 → 悬空/崩溃</span></span></code><code><span leaf=""> Test* p3 = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">Test</span>();</span></code><code><span leaf=""> <span class="code-snippet__function">shared_ptr<Test> </span><span class="code-snippet__function"><span class="code-snippet__title">s5</span></span><span class="code-snippet__function"><span class="code-snippet__params">(p3)</span></span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// delete p3; // 智能指针析构时再次 delete</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ❌ 不要混用 new / new[] → 匹配 unique_ptr<T[]></span></span></code><code><span leaf=""> unique_ptr<<span class="code-snippet__type">int</span>[]> arr_u = <span class="code-snippet__built_in">make_unique</span><<span class="code-snippet__type">int</span>[]>(<span class="code-snippet__number">5</span>); <span class="code-snippet__comment">// ✅ 数组专用</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// unique_ptr<int> arr_bad(new int[5]); // 错误,析构用 delete 而非 delete[]</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ==================== 5. 最佳实践 ====================</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 优先:make_unique / make_shared,避免裸指针</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 优先:unique_ptr > shared_ptr(性能更高)</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 循环引用必须用 weak_ptr</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 不要手动管理裸指针 + 智能指针混用</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 不要返回局部对象指针/引用</span></span></code><code><span leaf=""> <span class="code-snippet__comment">// ✅ 多线程:shared_ptr 引用计数安全,但对象访问不安全</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span leaf="">}</span>四、内存泄漏检测工具原理(valgrind)
4.1 valgrind 工作原理图
┌─────────────────────────────────────────────────────────────────────┐│ Valgrind 检测原理 │├─────────────────────────────────────────────────────────────────────┤│ ││ 原始程序 Valgrind 中运行 ││ ┌─────────┐ ┌─────────────────────────────┐ ││ │ 代码 │ │ Valgrind Core │ ││ └────┬────┘ │ ┌───────────────────────┐ │ ││ │ │ │ Valid-Value 表 │ │ ││ ▼ │ │ 每个字节对应8 bits │ │ ││ ┌─────────┐ │ │ 记录值是否已初始化 │ │ ││ │ CPU执行 │ │ └───────────────────────┘ │ ││ └─────────┘ │ ┌───────────────────────┐ │ ││ │ │ Valid-Address 表 │ │ ││ │ │ 每个字节对应1 bit │ │ ││ │ │ 记录地址是否可读写 │ │ ││ │ └───────────────────────┘ │ ││ │ │ ││ │ ┌───────────────────────┐ │ ││ │ │ 模拟CPU │ │ ││ │ │ 检查每次内存操作 │ │ ││ │ └───────────────────────┘ │ ││ └─────────────────────────────┘ ││ ││ 检测到的问题: ││ • 使用未初始化的内存 ││ • 内存越界读写 ││ • 内存泄漏 ││ • 重复释放 ││ │└─────────────────────────────────────────────────────────────────────┘
4.2 使用 valgrind 检测内存泄漏
# 编译程序(需要包含调试信息)g++ -g -o myprogram myprogram.cpp# 使用 valgrind 检测valgrind --leak-check=full --show-leak-kinds=all ./myprogram# 常用选项valgrind --tool=memcheck --leak-check=full --track-origins=yes ./myprogram
<span leaf=""><span class="code-snippet__comment">// 文件:valgrind_test.cpp</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><iostream></span></span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">include</span></span><span class="code-snippet__meta"> </span><span class="code-snippet__meta"><span class="code-snippet__string"><cstdlib></span></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> std;</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__comment">// 一个有内存泄漏的程序</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">leaky_function</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__type">int</span>[<span class="code-snippet__number">100</span>];</span></code><code><span leaf=""> <span class="code-snippet__comment">// 忘记 delete[] p</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">use_uninitialized</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p = (<span class="code-snippet__type">int</span>*)<span class="code-snippet__built_in">malloc</span>(<span class="code-snippet__built_in">sizeof</span>(<span class="code-snippet__type">int</span>));</span></code><code><span leaf=""> <span class="code-snippet__comment">// 未初始化就使用</span></span></code><code><span leaf=""> cout << *p << endl; <span class="code-snippet__comment">// 使用未初始化的值</span></span></code><code><span leaf=""> <span class="code-snippet__built_in">free</span>(p);</span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">double_free</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__type">int</span>* p = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">10</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> p;</span></code><code><span leaf=""> <span class="code-snippet__keyword">delete</span> p; <span class="code-snippet__comment">// 重复释放</span></span></code><code><span leaf="">}</span></code><code><span leaf=""><br /></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__type">int</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">main</span></span><span class="code-snippet__function"><span class="code-snippet__params">()</span></span><span class="code-snippet__function"> </span>{</span></code><code><span leaf=""> <span class="code-snippet__built_in">leaky_function</span>();</span></code><code><span leaf=""> <span class="code-snippet__built_in">use_uninitialized</span>();</span></code><code><span leaf=""> <span class="code-snippet__comment">// double_free(); // 取消注释会触发错误</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span leaf="">}</span>五、快速参考卡片
⚠️ 版权声明
本内容已做唯一性标记(文章 ID:1560),受版权保护,未经本站书面授权,禁止任何形式的转载、复制或搬运。侵权必究,本站保留依法维权的权利。
还没有评论,来说两句?