You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中已有拷贝构造函数为什么还需要实现赋值运算符?

关于C++三法则与赋值运算符实现的解答

为什么只实现拷贝构造函数不足以让类正常运行

首先要区分拷贝构造和拷贝赋值的触发场景:

  • 拷贝构造是在创建新对象时,用另一个已有对象初始化触发,比如dumb_array a = b;、dumb_array a(b);
  • 拷贝赋值运算符operator=是在两个已存在的对象之间做赋值操作时触发,比如你已经定义了dumb_array a(10); dumb_array b(5);,再执行a = b;就会调用operator=

你给出的代码里没有自定义operator=,编译器会自动生成默认的拷贝赋值运算符,默认实现是对所有成员做浅拷贝,会直接导致两个严重问题:

  1. 内存泄漏:赋值目标对象原来持有的堆内存没有被释放,指针被直接覆盖,对应的内存永远无法回收
  2. 重复释放:赋值完成后两个对象的指针会指向同一块堆内存,两个对象析构时会对同一块内存执行两次delete[],触发未定义行为,大概率直接崩溃

比如下面的测试代码就会触发问题:

int main() {
    dumb_array arr1(10);
    dumb_array arr2(5);
    arr2 = arr1; // 调用默认operator=,直接触发异常
    return 0;
}

什么是三法则(Rule of Three)

三法则是C++的经典编码约定:如果你的类需要自定义析构函数、拷贝构造函数、拷贝赋值运算符三者中的任意一个,那么三者都需要自定义。
这个规则的核心逻辑是:需要自定义这三个函数的任意一个,就说明类需要自行管理默认语法无法自动管理的资源(比如堆内存、文件句柄、网络连接等),默认的浅拷贝语义无法满足资源管理的需求,三个函数的资源管理逻辑是强相关的,必须配套实现。

正确的operator=实现参考

推荐用复制交换(copy-and-swap)的写法,既安全又可以复用已有的拷贝构造逻辑:
首先给类添加友元swap函数:

friend void swap(dumb_array& first, dumb_array& second) noexcept {
    // 交换所有成员
    std::swap(first.mSize, second.mSize);
    std::swap(first.mArray, second.mArray);
}

然后实现operator=:

dumb_array& operator=(dumb_array other) { // 按值传参,自动调用拷贝构造生成临时对象
    swap(*this, other); // 交换本对象和临时拷贝的内容
    return *this;
} // 临时对象other出作用域自动析构,原来的旧资源会被自动释放

这种写法天然避免了自赋值问题,同时异常安全,如果拷贝构造抛出异常,本对象的内容不会被修改。

内容的提问来源于stack exchange,提问作者Sachin Palande

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 01:06:07