0Pricing
C++ Academy · 课时

三法则与五法则

正确管理复制和移动

三法则与五法则 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

三法则

如果一个类需要自定义析构函数,那么它几乎总是也需要自定义拷贝构造函数和拷贝赋值运算符。这三者总是成套出现。

为什么是三个

管理裸资源的类必须定义资源如何被销毁、复制和赋值——否则编译器生成的浅拷贝会导致重复释放。

#include <iostream>

class Bad {
    int* p;
public:
    Bad(int v) : p(new int(v)) {}
    ~Bad() { delete p; }
    // default copy => two objects delete the same p!
};

自定义拷贝构造函数

正确的拷贝构造函数会执行深拷贝,分配属于自身的资源,而不是与其他对象共享资源。

#include <iostream>

class Box {
    int* p;
public:
    Box(int v) : p(new int(v)) {}
    Box(const Box& o) : p(new int(*o.p)) {}   // deep copy
    ~Box() { delete p; }
    int get() const { return *p; }
};

int main() {
    Box a(5);
    Box b = a;   // independent copy
    std::cout << b.get() << "\n";
}

自定义拷贝赋值

拷贝赋值必须释放旧资源,防止自赋值,并对新值执行深拷贝。

Box& operator=(const Box& o) {
    if (this != &o) {              // self-assignment guard
        delete p;
        p = new int(*o.p);
    }
    return *this;
}

五法则

C++11 增加了移动操作。如果您定义了五个特殊成员函数中的任意一个(析构函数、拷贝构造、拷贝赋值、移动构造、移动赋值),就应考虑将五个全部定义出来。

移动构造函数

移动构造函数会从临时对象中接管资源,并使源对象变为空——这比拷贝的代价低得多。

Box(Box&& o) noexcept : p(o.p) {
    o.p = nullptr;   // source left empty
}

移动赋值

移动赋值会释放当前资源,然后接管源对象的资源。

Box& operator=(Box&& o) noexcept {
    if (this != &o) {
        delete p;
        p = o.p;
        o.p = nullptr;
    }
    return *this;
}

将移动操作标记为 noexcept

移动操作应标记为 noexcept,这样容器(例如 std::vector)在重新分配时就能安全地使用它们。

零法则

最理想的做法是:不要直接拥有任何原始资源。使用 std::unique_ptr、std::vector 或 std::string,这样您就可以不定义五个特殊成员函数中的任何一个——编译器生成的默认版本就是正确的。

#include <memory>

class Good {
    std::unique_ptr<int> p;   // owns the resource for you
public:
    Good(int v) : p(std::make_unique<int>(v)) {}
    // no destructor, no copy/move needed
};

删除操作

如果拷贝没有意义,就将其删除:Box(const Box&) = delete;。这样可以有意地让类型只能移动或不可拷贝。

选择正确的法则

应以零法则为目标。只有在确实封装了标准库无法处理的原始资源时,才退而采用五法则。

快速检查

请测试您对三法则/五法则的理解。

回顾

您已经学习了三法则/五法则:管理原始资源意味着要一致地定义析构、拷贝和移动操作。请将移动操作标记为 noexcept。最理想的做法是使用标准 RAII 类型,遵循零法则,一个特殊成员函数都不定义。

常见问题解答

「三法则与五法则」课时是免费的吗?

是的 — 「三法则与五法则」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「三法则与五法则」这节课中我会学到什么?

正确管理复制和移动 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「三法则与五法则」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. RAII 原则
  2. 析构函数与清理
  3. 三法则与五法则
  4. 作用域守卫
← 返回 C++ Academy