c++内存 | 内存泄露 | 共享指针

github热门推荐 › c++内存 | 内存泄露 | 共享指针 (第 80 章)
文章工具

一、什么是内存泄漏

1.1 概念图解

┌─────────────────────────────────────────────────────────────────┐│                        内存泄漏示意图                            │├─────────────────────────────────────────────────────────────────┤│                                                                 ││   程序开始              运行中                程序结束          ││      ↓                    ↓                      ↓             ││   ┌──────┐            ┌──────┐               ┌──────┐          ││   │ 堆   │            │ 堆   │               │ 堆   │          ││   │ 空   │  ──────►   │ ████ │ ◄── 泄漏      │ ████ │ ◄── 无法释放││   └──────┘            │ ████ │               │ ████ │          ││                       └──────┘               └──────┘          ││                                                                 ││   分配内存 ✓              使用内存 ✓              释放内存 ✗    ││                                                                 │└─────────────────────────────────────────────────────────────────┘

1.2 指针重新赋值导致的内存泄漏

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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 常见内存泄漏场景

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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封装(构造时获取,析构时释放)

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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 智能指针完整实现(参考源码)

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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 智能指针使用示例

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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 移动赋值详解

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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 共享指针避坑

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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
C++ 片段需补全 main() 函数才能运行在实训台打开 →
<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),受版权保护,未经本站书面授权,禁止任何形式的转载、复制或搬运。侵权必究,本站保留依法维权的权利。