13.1 拷贝构造函数和拷贝赋值运算符

本文探讨了拷贝构造函数和拷贝赋值运算符在C++中的作用及实现细节,解释了它们如何避免内存管理和析构过程中的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拷贝构造函数接受一个const引用同类型的对象作为参数,将其每一个参数拷贝给需要初始化的对象;
拷贝赋值运算符重载=号,接受一个同类型的const引用对象,返回一个该类型的引用。

#include <string>

class HasPtr {
public:
    HasPtr(const std::string &s = std::string()) // 构造函数
        : ps(new std::string()), i(0) {}
    HasPtr(const HasPtr &obj) // 拷贝构造函数,注意参数是常量引用类型
        : ps(new std::string(*obj.ps)), i(obj.i) {}
    HasPtr & operator=(const HasPtr &rhs) { // 拷贝赋值函数,参数是常量引用,返回值是引用
        ps = new std::string(*rhs.ps); // 直接拷贝rhs的ps是致命错误
        i = rhs.i;
    }
    ~HasPtr() {
        delete ps;
    }
private:
    std::string *ps;
    int i;
};

struct X {
   X() { std::cout << "X()" << std::endl; }
   X(const X &x) { std::cout << "X(const X&)" << std::endl; }
   X &operator=(const X &x) {
      std::cout << "X=" << std::endl;
      return *this;
   }
   ~X() { std::cout << "~X()" << std::endl; }
};

int main() {
   X a;
   X b(a);
   X c;
   c = a;
}

在这里插入图片描述
问题是,改变c和a的赋值方式:

X c = a;

输出变成:
在这里插入图片描述
不再使用拷贝赋值运算符,而是使用拷贝构造函数。
个人理解是,此处执行过程不是先默认构造c,然后调用拷贝赋值运算符,而是直接优化成一次拷贝构造。

如果一个类需要析构函数,那么几乎可以肯定它也需要拷贝构造和拷贝赋值运算符函数。
例如类中的一个数据成员是new出来的指针,如果使用默认的拷贝构造和拷贝赋值,指针会被复制,当原始对象析构时,指针指向的对象被delete,而新对象在析构时,会重复delete这片内存,会发生未定义行为。或者存在内存已经被释放,但是还有其他对象含有指向这一内存的指针,读取会发生错误。

如果一个类需要拷贝构造函数,则它一定需要拷贝复制运算符,反之亦然。但它不一定需要析构函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值