Menu
CoddyTech

C++ 中的智能指针

本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 15 课,共 104 课。

智能指针是包装类,可以为你自动管理堆内存。当指针超出作用域时,它们会清理内存,因此你不再需要手动调用 delete。

包含 <memory> 头文件,以使用智能指针。

unique_ptr:独占所有权。同一时间只能有一个指针拥有该资源。

#include <memory>

std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack();  // 像普通指针一样使用

// 不能复制,但可以转移所有权
std::unique_ptr<Player> player2 = std::move(player);
// player 现在是 nullptr

shared_ptr:共享所有权。多个指针可以拥有同一资源。最后一个所有者销毁后,内存才会释放。

std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1;  // 两者都拥有该资源

std::cout << p1.use_count();  // 输出 2

weak_ptr - shared_ptr 的非拥有型观察者。可用于打破循环引用。

std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;

if (auto locked = weak.lock()) {  // 转换为 shared_ptr
    locked->attack();
}

单一所有权时,默认使用 unique_ptr。多个对象需要共享资源时,使用 shared_ptr。使用 weak_ptr 进行观察,而不延长生命周期。

优先使用 make_unique 和 make_shared,而不是直接使用 new。

challenge icon

挑战

简单

我们来构建一个文档共享系统,演示智能指针的不同所有权模型。你将看到 unique_ptr 如何确保独占所有权,shared_ptr 如何允许多个所有者,以及 weak_ptr 如何在不影响对象生命周期的情况下观察对象。

你将创建两个文件来组织代码:

  • Document.h:定义一个表示可共享文档的 Document 类。它应包含:
    • 一个私有的 title 属性(字符串)
    • 一个接收标题并打印 "Document created: <title>" 的构造函数
    • 一个打印 "Document deleted: <title>" 的析构函数
    • 一个返回标题的 getTitle() 方法
  • main.cpp:从输入中读取文档标题,然后演示全部三种智能指针类型:
    • 创建一个指向标题为输入内容的 Document 的 unique_ptr
    • 打印 "Unique owner: <title>"
    • 使用 std::move 将所有权转移给另一个 unique_ptr
    • 打印 "Ownership transferred"
    • 创建一个指向新 Document 的 shared_ptr,其标题为 "SharedDoc"
    • 创建第二个指向同一文档的 shared_ptr
    • 使用 use_count() 打印 "Shared owners: <count>"
    • 从其中一个共享指针创建一个 weak_ptr
    • 使用 lock() 通过弱指针访问文档,并打印 "Weak access: <title>"

记得包含 <memory>,以使用智能指针。使用 std::make_unique 和 std::make_shared 创建智能指针。析构函数输出的信息可以帮助你了解程序结束时每个文档何时被自动清理。

在 main.cpp 中使用 #include "Document.h" 包含头文件。

亲手试试

#include <iostream>
#include <memory>
#include <string>
#include "Document.h"

using namespace std;

int main() {
    string inputTitle;
    cin >> inputTitle;

    // TODO:创建一个指向 Document 的 unique_ptr,并用 inputTitle 作为标题
    // 使用 std::make_unique

    // TODO:打印 "Unique owner: <title>"

    // TODO:使用 std::move 将所有权转移给另一个 unique_ptr

    // TODO:打印 "Ownership transferred"

    // TODO:创建一个指向新 Document 的 shared_ptr,标题为 "SharedDoc"
    // 使用 std::make_shared

    // TODO:创建第二个指向同一文档的 shared_ptr

    // TODO:使用 use_count() 打印 "Shared owners: <count>"

    // TODO:从其中一个 shared_ptr 创建一个 weak_ptr

    // TODO:使用 lock() 通过 weak_ptr 访问文档
    // 并打印 "Weak access: <title>"

    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器