C++ 智能指针

31 2025 年 7 月 | 阅读 8 分钟

在 C++ 编程语言中,智能指针是标准库(<memory>)中提供的类模板,它们可以自动管理动态分配的内存。它们充当原始指针的包装器,但具有内置的内存管理功能。这些指针主要用作模板,因此我们可以为任何类型的内存创建智能指针。

智能指针有助于防止 C++ 编程中的一些常见内存问题。其中一些问题如下:

  • 内存泄漏
  • 悬空指针
  • 重复删除
  • 未管理的资源

智能指针遵循 RAII(资源获取初始化)原则,这意味着内存会被自动获取和释放。我们将实现智能指针,使其能够释放未使用的资源内存。
首先,我们必须创建一个带有 指针、重载运算符(->, *)和 析构函数 的类。之后,当其对象超出作用域时,析构函数将自动调用,并且动态分配的内存也将自动删除。

C++ 中的智能指针示例

让我们通过一个示例来说明 C++ 中的智能指针。

示例

编译并运行

输出

100  

说明

在此示例中,我们演示了一个自定义 SmartPtr 类的智能指针。它管理一个动态分配的整数,并在其析构函数中自动释放内存,从而防止内存泄漏。之后,重载的 * 运算符允许像普通指针一样访问被指向的值。

使用模板类的 C++ 智能指针示例

上面的示例仅适用于 int。现在,我们将创建一个适用于所有 数据类型 的模板。让我们通过另一个示例来说明 C++ 中使用模板类的智能指针。

示例

编译并运行

输出

100  

说明

在此示例中,我们使用 C++ 模板定义了一个通用的智能指针类 SmartPtr,它允许它管理任何类型的动态分配的对象。之后,它会在析构函数中自动删除资源,这有助于防止内存泄漏。重载的 * 和 -> 运算符使得指针般的行为能够访问和修改对象。

智能指针的类型

C++ 中有几种智能指针。其中一些如下:

Smart Pointers in C++

Unique_ptr

unique_ptr 是一种智能指针,可确保在任何给定时间只有一个 unique_ptr 可以拥有特定资源,从而防止内存泄漏和不可预测的行为。它表示关联的资源会在 unique_ptr 退出其作用域时自动释放,或通过 move() 方法手动移除。

语法

它具有以下语法:

C++ 中 unique_ptr 的特性

C++ 中 unique_ptr 的一些特性如下:

  • 它唯一拥有一个资源。
  • 它不能被复制,只能转移。
  • 当 unique_ptr 超出作用域时,它会自动删除对象。

Unique_ptr C++ 示例

让我们通过一个示例来说明 C++ 中的 Unique_ptr 示例。

示例

编译并运行

输出

100
100  

说明

在此示例中,我们演示了 unique_ptr 如何管理 Rectangle 对象的动态内存。指针的所有权通过 move() 函数从 P1 转移到 P2,从而确保一次只有一个唯一指针拥有该对象。之后,使用箭头运算符访问面积。

Shared_ptr

在 shared_ptr 中,我们可以在同一时间将多个对象指向单个指针。使用 use_count() 方法维护一个引用计数来表示对象。

语法

它具有以下语法:

C++ 中 shared_ptr() 函数的特性

C++ 中 shared_ptr() 函数的一些特性如下:

  • 它允许对资源进行共享所有权。
  • 它在内部使用引用计数。
  • 当最后一个 shared_ptr 被销毁时,内存将被删除。

Shared_ptr C++ 示例

让我们通过一个示例来说明 C++ 中的 shared_ptr。

示例

编译并运行

输出

100
100
100
2  

说明

在此示例中,我们演示了 C++ 中的 shared_ptr。首先,我们有两个智能指针(P1 和 P2),它们共享 Rectangle 对象的拥有权。之后,两个指针都可以访问 area() 方法和 use_count() 方法,该方法显示有多少指针正在管理该对象。

Weak_ptr

weak_ptr 与 shared_ptr 类似。weak 和 shared_ptr 的主要区别在于它不维护引用计数,并且对象对指针没有强引用。此属性可能导致死锁,因为不同的对象将尝试持有指针。

语法

它具有以下语法:

C++ 中 weak_ptr 的特性

C++ 中 weak_ptr 的一些特性如下:

  • 对常用共享资源的非拥有者引用。
  • 它用于打破可能发生在一个和多个 shared_ptr 实例相互引用的循环引用,这有助于防止内存泄漏。
  • 它不影响引用计数。

Weak_ptr C++ 示例

让我们通过一个示例来说明 C++ 中的 weak_ptr。

示例

编译并运行

输出

Parent use count: 1
Child use count: 1
Child destroyed
Parent destroyed
End of scope reached. 

说明

在此示例中,我们演示了 weak_ptr 来避免循环引用。在这里,Parent 类持有 Child 类的 shared_ptr,而 Child 类持有 Parent 类的 weak_ptr。它确保当两个类都超出作用域时,它们的析构函数都会被正确调用,从而防止由循环 shared_ptr 依赖关系引起的内存泄漏。

C++ 中原始指针和智能指针的区别

C++ 中原始指针和智能指针的一些区别如下:

特点原始指针 (*)智能指针(std::unique_ptr, std::shared_ptr 等)
内存管理它需要手动管理,并且必须使用 new 和 delete。它具有自动内存管理。这意味着内存会在不再需要时被管理和释放。
所有权语义无所有权跟踪所有权定义明确(唯一、共享或弱)
内存泄漏风险内存泄漏的风险很高,因为用户必须记住手动删除任何动态分配的内存。内存泄漏的风险很低,因为托管内存会自动释放。
悬空指针如果过早删除,则可能发生由于基于作用域的销毁,发生概率降低
复制行为可自由复制取决于类型(unique_ptr 不可复制,shared_ptr 可复制)
线程安全它本身不是线程安全的。shared_ptr 对引用计数是线程安全的;其他可能不是。
语法复杂度它具有简单的语法。它稍微冗长一些(例如,std::make_shared<T>())。
支持自定义删除器仅手动删除它支持自定义删除器(尤其是在 unique_ptr 中)。
STL 兼容性与容器一起使用不安全。它被设计成可以与 STL 容器很好地协同工作。
C++ 版本要求它在所有 C++ 版本中都可用。它需要 C++11 或更高版本。

结论

总之,C++ 智能指针通过处理资源分配来自动简化内存管理。它们有助于消除内存泄漏、悬空指针和手动删除调用等问题。std::unique_ptr、std::shared_ptr 和 std::weak_ptr 等智能指针各自服务于不同的所有权需求。
这些指针支持 RAII,从而促进了安全且更易于维护的代码。智能指针在现代 C++ 中对于干净高效的内存使用是必不可少的。采用它们可以构建更健壮、无错误的应用程序。

智能指针选择题

1) 如果我们尝试在 C++ 中复制 std::unique_ptr,会发生什么?

  1. 程序编译并按预期工作
  2. 对象已被复制
  3. 发生编译时错误
  4. 抛出运行时异常
 

答案: c) 发生编译时错误


2) 与 C++ 中的原始指针相比,使用智能指针的主要优点是什么?

  1. 它们增加了程序的规模
  2. 它们有助于防止内存泄漏
  3. 它们需要手动内存管理
  4. 它们会减慢代码速度
 

答案: b) 它们有助于防止内存泄漏


3) 为什么 std::unique_ptr 在 C++ 中被优先用于资源的单一所有权?

  1. 它确保了特殊所有权和自动删除
  2. 它支持复制
  3. 它允许共享访问
  4. 它会关闭动态内存
 

答案: a) 它确保了特殊所有权和自动删除


4) std::shared_ptr 在 C++ 中如何管理资源的生命周期?

  1. 它立即删除资源
  2. 它使用手动删除
  3. 当最后一个 shared_ptr 被销毁时,它会删除资源
  4. 它从不删除资源
 

答案: c) 当最后一个 shared_ptr 被销毁时,它会删除资源


5) 当 unique_ptr 被移动到另一个 unique_ptr 时会发生什么?

  1. 两者都指向同一个资源
  2. 原始指针被复制
  3. 什么也没发生
  4. 所有权已转移;原始指针变为 null
 

答案: d) 所有权已转移;原始指针变为 null