C++中的深拷贝和浅拷贝

C++中的深拷贝和浅拷贝

当有需要的时候,C++编译器会为类生成默认的内联public复制构造函数,这些复制构造函数只是简单的进行位拷贝,即将一个对象的成员变量的值逐位拷贝给另外一个对象,以完成对象的初始化。
class People
{
public:
    People(int age) 
    {
       this->age = age;
    }
public:
    int age;
};
int main()
{
    int tempAge = 3;
    People ZhangSan(tempAge);
    People LiSi(ZhangSan); 
    return 0;
}
当执行People LiSi(ZhangSan)时就调用了编译器生成的默认复制构造函数,当执行完这句之后LiSi的age变量就和ZhangSan的age的值得一模一样。
这种复制构造函数只是对变量的值进行拷贝。所以当类中含有指针指针成员时,或者说类中的变量需要动态申请内存时,这种构造复制构造函数就不适用了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
class Name
{
public:
    Name(char* name,int length)
    {
        //不能不加this
        this->name = new char[length];
        this->length =length;
        strcpy(this->name,name);
    }
    void printName()
    {
        cout<<"The Address of the Name  "<<(void*)this->name<<endl;
        cout<<this->name<<endl;
    }
    ~Name()
    {
        delete[] this->name;
    }
    void setName(char* name,int length)
    {
        if(this->length <length)
        {
            delete[] name;
            name  = new char[length];
        }
        strcpy(this->name,name);
    }
private:
    char* name;
    int length;
};
int main()
{
    char* temp="ZhangSan";
    Name ZhangSan(temp,strlen(temp));
    Name LiSi(ZhangSan);

    ZhangSan.printName();
    LiSi.printName();

    temp = "Changed";
    ZhangSan.setName(temp,strlen(temp));

    ZhangSan.printName();
    LiSi.printName();
    return 0;
}
如果使用编译器生成的默认的复制构造函数,上述代码的运行结果如下:
The Address of the Name  0x611600
ZhangSan
The Address of the Name  0x611600
ZhangSan
The Address of the Name  0x611600
Changed
The Address of the Name  0x611600
Changed

从上诉结果可以看出:张三的Name跟LiSi的name实质上指向的是同一块内存空间。因为默认复制构造函数的本质就是值拷贝,形式如下:
Name(Name& temp) 
{
    this->name =temp.name;
    this->length = temp.length;
}

在复制的过程中只是单纯的将temp的nam指针复制给当前对象,所以会发生两个对象的name会指向同一块内存地址。


ZhangSan 和LiSi的name指向同一块内存区域,当ZhangSan把自己的name修改之后,LiSi的name也会跟着修改,ZhangSan对自己的name的任何修改都会影响LiSi的name。这样是极其危险的,特别容易产生野指针或者释放已经被释放的内存区域。

针对上述这种情况我们自己手动添加复制构造函数如下:
    Name(Name& temp)
    {
        this->name = new char[temp.length];
        this->length = temp.length;
        if(temp.length!=0)
            strcpy(this->name,temp.name);
    }
再次运行上次的程序:
The Address of the Name  0x4c1600
ZhangSan
The Address of the Name  0x4c1630
ZhangSan
The Address of the Name  0x4c1600
Changed
The Address of the Name  0x4c1630
ZhangSan
从结果可以看出ZhangSan的name和LiSI的name指向不同的地址,在执行了setName()之后LiSi的name并没有受到影响。内存分布如下:

所以,如果我们创建的类中有指针时,我们就要注意是不是应该给它手动添加复制构造函数,以避免浅拷贝造成个各种问题。
设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。 设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。
C++ 中,拷贝是一种数据传递的方式,用于创建新对象并初始化为现有对象的状态。深拷贝浅拷贝主要涉及到复杂的数据结构,尤其是指针或引用类型的对象。 1. **浅拷贝** (Shallow Copy):当对包含指向动态分配内存的对象的简单值类型变量进行复制时,通常就是浅拷贝。它只是复制了对象的引用,并不会复制实际内容。例如,对于基本类型、栈上的数据以及没有成员指针的对象,浅拷贝就足够了。浅拷贝的对象之间修改会影响到彼此。 ```cpp int a = 5; int b = a; // 浅拷贝,ba共享相同的整数值 class Point { public: int x, y; }; Point p1(10, 20); Point p2 = p1; // 对于类 Point,这里也是浅拷贝,p2引用了p1的地址 ``` 2. **深拷贝** (Deep Copy):如果对象包含指针或引用,或者更复杂的结构(如自定义容器或有嵌套的对象),那么复制的是整个对象的内容,包括所有底层的动态分配的内存。这需要显式地实现拷贝构造函数赋值运算符,或者使用 `std::copy` 等库函数。深拷贝会创建一份独立的副本,修改一个副本不会影响到原始对象。 ```cpp // 深拷贝示例 Point p3(p1); // 对于类 Point,这是深拷贝,创建了一个新的 Point 实例并复制了其数据 std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2 = vec1; // 对于 std::vector,这也是深拷贝,每个元素都单独复制了一次 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值