C++智能指针:它们是什么以及何时使用?教程

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么你的程序“吃”光了所有内存,以及如何修复?

\n\n

你是否曾经用C++编写过一个应用程序,它运行得非常好,直到你关闭窗口?然后你发现它“吃”掉了数GB的内存,却一个字节都没有归还?或者更糟的是,你的程序突然崩溃,并出现神秘的segmentation fault错误,而你花了几个小时寻找忘记调用delete的地方?

\n\n

如果是这样——欢迎加入我们的行列。在C++中手动管理内存就像玩电锯杂耍:理论上可行,但最好还是交给专业人士。或者,在我们的例子中,交给智能指针(smart pointers)。

\n\n

今天,我们将深入探讨这些“猛兽”是什么,它们有哪些类型,以及最重要的是,何时使用哪一种。本文改编自Stack Overflow上一个获得数千次浏览的著名问题。我们将让它变得清晰易懂、生动有趣,并附上示例。开始吧!

\n\n

什么是智能指针?简单来说

\n\n

想象一个普通指针(int* ptr = new int(5);)。它就像一把通往资源储藏室的钥匙。你打开了储藏室(分配了内存),但如果你丢了钥匙或忘了关门——资源将永远丢失。这就是内存泄漏。

\n\n

智能指针是一把“自动关闭的钥匙”。它是一个包装类,内部存储一个普通指针,并在对象不再需要时自动调用delete(或delete[])。当智能指针超出作用域时,其析构函数会触发并释放内存。是魔法吗?不,是RAII(资源获取即初始化)——C++的基石之一。

\n\n

从C++11开始,智能指针已成为标准库的一部分(<memory>)。忘掉auto_ptr吧(它已过时且危险)。现在我们有三位“勇士”:

\n\n
    \n
  • std::unique_ptr — 唯一所有者。
  • \n
  • std::shared_ptr — 具有“集体所有权”的资源。
  • \n
  • std::weak_ptr — 不干扰生活的“观察者”。
  • \n
\n\n

让我们逐一用通俗易懂的方式和代码来解析。

\n\n

std::unique_ptr: “这是我的,谁也别想碰!”

\n\n

std::unique_ptr 是最简单、最快的智能指针。它保证对象的所有权只属于一个指针。你不能复制unique_ptr,但可以移动它(转移所有权)。

\n\n

何时使用?几乎任何时候你在堆上创建对象,并且知道它在整个生命周期中只有一个所有者。

\n\n

示例:创建和使用

\n\n
#include <iostream>\n#include <memory>  // 用于智能指针\n\nclass Robot {\npublic:\n    Robot(const std::string& name) : name_(name) {\n        std::cout << "机器人 " << name_ << " 已激活!\\n";\n    }\n    void speak() const { std::cout << name_ << ": 你好,世界!\\n"; }\n    ~Robot() { std::cout << "机器人 " << name_ << " 已被销毁。\\n"; }\nprivate:\n    std::string name_;\n};\n\nint main() {\n    // 创建 unique_ptr(永远不要使用 new!)\n    std::unique_ptr<Robot> r1 = std::make_unique<Robot>("R2-D2");\n\n    r1->speak();  // 像普通指针一样使用\n\n    // std::unique_ptr<Robot> r2 = r1; // 错误!不能复制\n    std::unique_ptr<Robot> r2 = std::move(r1); // 转移所有权\n\n    if (!r1) {\n        std::cout << "r1 现在为空,所有权已转移给 r2\\n";\n    }\n\n    r2->speak();  // 正常工作\n    // 这里 r2 将超出作用域,机器人将被自动销毁\n    return 0;\n}
\n\n

重要提示: 使用 std::make_unique<T>(args...) 而不是 new

博客

书籍推荐