编程C++ 中级开发者

解释普通指针和智能指针(例如,std::unique_ptr)之间的区别。在 C++ 中,为什么智能指针使程序更可靠?

用 Hintsage AI 助手通过面试

答案。

背景:

普通(原始)指针是 C++ 中处理动态内存的传统机制。这是一种通用的抽象机制,但遗憾的是,很容易出错:内存泄漏、双重删除、悬挂指针错误。因此,自 C++11 起,标准库引入了智能指针——模板类(std::unique_ptr、std::shared_ptr、std::weak_ptr),它们自动管理对象的生命周期。

问题:

在使用普通指针时,内存的分配和释放责任在于程序员。释放内存中的错误会导致内存泄漏、数据损坏和程序崩溃。尤其在处理异常或将指针传递给其他函数时,情况会特别复杂。

解决方案:

智能指针封装了分配的内存,并在没有所有者时自动释放它。它们实现了 RAII。std::unique_ptr 提供独占所有权,std::shared_ptr 提供共享所有权,std::weak_ptr 提供非控制所有权(以防止“引用循环”)。

代码示例:

#include <memory> void foo() { std::unique_ptr<int> p = std::make_unique<int>(5); // 即使在异常情况下,内存也会被释放 // ... }

关键特性:

  • 智能指针在销毁时自动释放资源
  • std::unique_ptr 禁止复制,只允许移动语义(move)
  • std::shared_ptr 实现“引用计数”

设问陷阱。

可以在通过 new[] 创建的数组中使用 std::unique_ptr 吗?

不行,数组应使用 std::unique_ptr<T[]>:这样会调用 delete[] 而不是 delete。

std::unique_ptr<int[]> arr(new int[10]);

标准智能指针能否防止所有可能的内存泄漏?

不行。例如,std::shared_ptr 之间的循环引用会导致内存泄漏。为打破这种循环,可以使用 std::weak_ptr。

智能指针能否“删除”同一对象两次?

不行,前提是不违反所有权逻辑(不使用原始指针!)。如果手动复制原始指针,则销毁可能会发生两次。

常见错误和反模式

  • 复制 std::unique_ptr 会导致编译错误
  • 同时使用智能指针和原始指针指向同一对象
  • 不使用 std::weak_ptr 解决环形依赖

实际案例

负面案例

使用原始指针,手动释放内存,在抛出异常时不会释放内存。

优点:

  • 在简单任务中明显

缺点:

  • 定期发生内存泄漏
  • 潜在的双重删除
  • 代码难以维护

正面案例

使用 std::unique_ptr 和 std::make_unique 创建对象并将其传递至函数。

优点:

  • 几乎不可能发生内存泄漏
  • RAII 接口,简单的所有权和对象传递

缺点:

  • 需要理解移动语义和标准库的使用