[Effective C++]条款12:复制对象时勿忘每一个成分

在C++中,拷贝构造函数和拷贝赋值操作符是用于管理对象拷贝行为的两个重要成员函数,如果不进行自定义实现,编译器默认会默认实现这两个函数。
1、自定义对象,内部属性都是基本数据类型
编译器默认行为:

  • 如果类的所有成员变量都是基本数据类型(如int、flaot、double等),编译器会自动生成默认的拷贝构造函数靠拷贝赋值操作符。這些默认实现会逐个拷贝每个成员变量的值。
  • 采用浅拷贝方式。对于基本数据类型,浅拷贝是安全的,不会引发问题。
class SimpleClass {
public:
    int a;
    double b;
};

int main() {
    SimpleClass obj1;
    obj1.a = 10;
    obj1.b = 3.14;

    // 调用默认拷贝构造函数
    SimpleClass obj2 = obj1;

    // 调用默认拷贝赋值操作符
    SimpleClass obj3;
    obj3 = obj1;

    return 0;
}

2、自定义对象,内部属性存在其他自定义类型的对象,或者有数组类型
编译器默认行为:

  • 如果类的成员变量包含其他自定义类型的对象,编译器会递归调用這些对象的拷贝构造函数或拷贝赋值操作符。对于数组类型,编译器会逐个拷贝数组中的每个元素。
  • 编译器默认行为是浅拷贝,对于inner成员,会调用InnerClass的默认拷贝构造函数,如果InnerClass或数组元素是动态分配的资源,浅拷贝会导致双重释放问题。
class InnerClass {
public:
    int x;
};

class OuterClass {
public:
    InnerClass inner;
    int arr[3];
};

int main() {
    OuterClass obj1;
    obj1.inner.x = 10;
    obj1.arr[0] = 1;
    obj1.arr[1] = 2;
    obj1.arr[2] = 3;

    // 调用默认拷贝构造函数
    OuterClass obj2 = obj1;

    // 调用默认拷贝赋值操作符
    OuterClass obj3;
    obj3 = obj1;

    return 0;
}

3、对象存在继承关系,父类有自己的属性
编译器默认行为:

  • 如果类存在继承关系,编译器会先调用父类的拷贝构造函数或拷贝赋值操作符,然后再拷贝子类的成员变量。
  • 因为编译器默认采用的是浅拷贝的方式,如果父类或子类的成员变量涉及动态资源管理,会导致资源释放问题。
class Base {
public:
    int baseData;
};

class Derived : public Base {
public:
    int derivedData;
};

int main() {
    Derived obj1;
    obj1.baseData = 10;
    obj1.derivedData = 20;

    // 调用默认拷贝构造函数
    Derived obj2 = obj1;

    // 调用默认拷贝赋值操作符
    Derived obj3;
    obj3 = obj1;

    return 0;
}

4、手动实现拷贝构造函数和拷贝赋值操作符

  • 如果类的成员变量涉及动态资源管理(如指针、文件句柄等),必须手动实现拷贝构造函数和拷贝赋值操作符,采用深拷贝方式实现。
  • 手动实现深拷贝:
    • 在拷贝构造函数中,为新对象分配新的资源
    • 在拷贝赋值操作符中,先释放原有资源,再分配新的资源。
    • 注意自赋值检查,避免释放资源后访问无效内存。
class DeepCopyClass {
public:
    int* data;

    // 构造函数
    DeepCopyClass(int value) {
        data = new int(value);
    }

    // 拷贝构造函数
    DeepCopyClass(const DeepCopyClass& other) {
        data = new int(*other.data); // 深拷贝
    }

    // 拷贝赋值操作符
    DeepCopyClass& operator=(const DeepCopyClass& other) {
        if (this == &other) { // 自赋值检查
            return *this;
        }
        delete data; // 释放原有资源
        data = new int(*other.data); // 深拷贝
        return *this;
    }

    // 析构函数
    ~DeepCopyClass() {
        delete data;
    }
};

int main() {
    DeepCopyClass obj1(10);
    DeepCopyClass obj2 = obj1; // 调用拷贝构造函数
    DeepCopyClass obj3(20);
    obj3 = obj1; // 调用拷贝赋值操作符

    return 0;
}

思维导图笔记
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值