深拷贝与浅拷贝

概念

浅拷贝(shallow copy)

浅拷贝(Shallow Copy)是一种对对象进行复制的方式,它简单地将源对象的所有成员变量的值复制给目标对象。在浅拷贝中,如果对象中存在指针成员变量,那么只会复制指针的值,而不会复制指针所指向的实际数据。

具体来说,浅拷贝仅复制指针的值,使目标对象和源对象共享相同的内存块。这意味着如果源对象或目标对象修改了共享内存中的数据,那么另一个对象也会受到影响。这可能导致意外的行为和错误的结果。

深拷贝(Deep Copy)

深拷贝(Deep Copy)是一种对对象进行复制的方式,它会创建一个全新的对象,并将源对象的所有成员变量的值复制到目标对象中,包括指针所指向的实际数据。深拷贝确保目标对象和源对象具有独立的数据副本,彼此之间不会共享数据。

具体来说,深拷贝会递归地复制对象的所有成员变量,包括基本类型和指针类型。当遇到指针类型成员变量时,深拷贝会为目标对象分配新的内存空间,并将源对象指针所指向的实际数据复制到新的内存空间中。这样,即使源对象或目标对象修改了它们各自的数据,彼此之间不会相互影响。

 

在C++中,如果没有特别指定拷贝构造函数或赋值运算符,编译器会默认执行浅拷贝。但是如果你的类包含了如指针等需要手动管理内存的数据类型,那么就需要自行实现深拷贝,以避免可能的内存泄露或者未定义行为。

当一个类包含原始指针类型的成员,并且使用默认的拷贝构造函数进行浅拷贝时,会出现两个对象指向同一块内存的情况。这种情况下,当其中一个对象被析构并释放了内存后,另一个对象的成员指针就会成为悬空指针,指向已释放的内存。使用悬空指针可能导致程序出错、崩溃或产生不可预测的行为。为了避免这种情况,需要实现深拷贝,确保每个对象都有自己独立的内存副本。

代码示例

浅拷贝

MyClass类中,使用了默认的移动构造函数、复制构造函数、移动赋值函数和复制赋值函数。这些默认的特殊成员函数对于处理指针成员是不安全的,因为它们会执行浅拷贝,即拷贝指针本身而不是指针所指向的数据。这样,在对象复制或移动时,两个对象将共享相同的数据。

#include <iostream>

using namespace std;

class MyClass
{
public:
    // 默认构造函数
    MyClass();
    // 构造函数,传入参数data
    MyClass(int data);
    // 移动构造函数
    MyClass(MyClass &&) = default;
    // 复制构造函数
    MyClass(const MyClass &) = default;
    // 移动赋值函数
    MyClass &operator=(MyClass &&) = default;
    // 复制赋值函数
    MyClass &operator=(const MyClass &) = default;
    // 获取data的值
    void getData();
    // 设置data的值
    void setData(int data);
    // 销毁data
    ~MyClass();

private:
    // 定义data指针
    int *data;
};

MyClass::MyClass()
{
}

MyClass::MyClass(int data)
{
    // 创建一个int类型的指针,指向data
    this->data = new int(data);
}

void MyClass::getData()
{
    // 打印出data的值
    cout << *(this->data) << endl;
}

void MyClass::setData(int data)
{
    // 删除data指针
    delete this->data;
    // 创建新的data指针
    this->data = new int(data);
}

MyClass::~MyClass()
{
    // 销毁堆上的对象
    delete this->data;
    this->data = nullptr;
}

int main(int argc, char const *argv[])
{
    MyClass val1 = MyClass(10);
    // MyClass val2 = val1; // valid
    MyClass val2 = MyClass(val1);
    // 打印val1的值
    val1.getData();
    // 设置val2的值
    val2.setData(20);
    // 打印val1的值
    val1.getData();
    return 0;
}

这段代码的运行结果如下,可知对val2中的data的修改影响了val1

10
20

深拷贝

下面的代码实现了自定义的复制构造函数和赋值运算符重载函数,以执行深拷贝并避免共享数据。在复制构造函数MyClass::MyClass(const MyClass &other)中,首先创建了一个新的int类型的指针,并将其初始化为other.data所指向的值,从而创建了一个新的数据副本。

在赋值运算符重载函数MyClass &MyClass::operator=(const MyClass &other)中,首先删除了this->data指针当前指向的内存,然后创建了一个新的int类型的指针,并将其初始化为other.data所指向的值,从而创建了一个新的数据副本。

这样,在对象的复制或赋值过程中,每个对象都拥有自己独立的数据副本,彼此之间不会相互影响。

#include <iostream>

using namespace std;

class MyClass
{
public:
    // 默认构造函数
    MyClass();
    // 构造函数,传入参数data
    MyClass(int data);
    // 移动构造函数
    MyClass(MyClass &&) = default;
    // 复制构造函数
    MyClass(const MyClass &other);
    // 移动赋值函数
    MyClass &operator=(MyClass &&) = default;
    // 复制赋值函数
    MyClass &operator=(const MyClass &other);
    // 获取data的值
    void getData();
    // 设置data的值
    void setData(int data);
    // 销毁data
    ~MyClass();

private:
    // 定义data指针
    int *data;
};

MyClass::MyClass()
{
}

MyClass::MyClass(int data)
{
    // 创建一个int类型的指针,指向data
    this->data = new int(data);
}

MyClass::MyClass(const MyClass &other)
{
    // 复制构造函数,用于初始化MyClass对象
    this->data = new int(*(other.data));
}

MyClass &MyClass::operator=(const MyClass &other)
{
    // 删除data指针
    delete this->data;
    // 创建新的data指针
    this->data = new int(*(other.data));
    return *this;
}

void MyClass::getData()
{
    // 打印出data的值
    cout << *(this->data) << endl;
}

void MyClass::setData(int data)
{
    // 删除data指针
    delete this->data;
    // 创建新的data指针
    this->data = new int(data);
}

MyClass::~MyClass()
{
    // 销毁堆上的对象
    delete this->data;
    this->data = nullptr;
}

int main()
{
    MyClass val1 = MyClass(10);
    // MyClass val2 = val1; // valid
    MyClass val2 = MyClass(val1);
    // 打印val1的值
    val1.getData();
    // 设置val2的值
    val2.setData(20);
    // 打印val1的值
    val1.getData();
    return 0;
}

这段代码的运行结果如下,可知对val2中的data的修改没有影响val1

10
10

 

------本页内容已结束,喜欢请分享------

文章作者
能不能吃完饭再说
隐私政策
PrivacyPolicy
用户协议
UseGenerator
许可协议
NC-SA 4.0


© 版权声明
THE END
喜欢就支持一下吧
点赞28赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片