Error[8]: Undefined offset: 5, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

概述C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝

对于普通的类型来说,拷贝没什么大不了的。

int a = 0;int b = a;

不会出现任何问题。

而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。

浅拷贝

首先来说说我们常遇到的浅拷贝的情况。

#include <stdio.h> class student{public:    student()      // 构造函数,p指向堆中分配的一空间    {        _name = new char(100);        printf("默认构造函数\n");    }    ~student()     // 析构函数,释放动态分配的空间    {        if (_name != NulL)        {            delete _name;            _name = NulL;            printf("析构函数\n");        }    }private:    char * _name;     // 一指针成员};int main(){    student a;    student b(a);   // 复制对象    return 0;}

这段代码乍看之下没什么毛病,通过类的默认构造函数将 a 复制给 b ,但是一旦运行就会程序崩溃。
经过我的刻苦学习与钻研,终于发现其中的问题所在。
由于我的类没有拷贝构造函数,所以student b(a)会调用,编译器自动生成的一个默认拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
浅拷贝:

@H_419_28@

浅拷贝只是拷贝了指针,并没有创建新的空间,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃。

浅拷贝使得 a 和 b 指向同一块内存,任何一方的变动都会影响到另一方。

由于 a 和 b 指向的是同一块内存空间,当 a 释放了后,b 指向的内存空间不复存在,所以会出现内存泄露的情况。

如何避免浅拷贝害人呢?
养成自定义拷贝构造函数的习惯,当显式定义了拷贝构造函数后,编译器就会调用拷贝构造函数了,为了不出现程序崩溃,请使用自定义拷贝构造函数,当然我们自己如果把代码写成了浅拷贝的形式,那也不是不可能的事。

深拷贝
// 使用自定制拷贝构造函数,完成深拷贝!!!class A{public:    A()      // 构造函数,p指向堆中分配的一空间    {        m_pdata = new char(100);        printf("默认构造函数\n");    }    A(const A& r)    // 拷贝构造函数    {        m_pdata = new char(100);    // 为新对象重新动态分配空间        memcpy(m_pdata, r.m_pdata, strlen(r.m_pdata));        printf("copy构造函数\n");    }    ~A()     // 析构函数,释放动态分配的空间    {        if (m_pdata != NulL)        {            delete m_pdata;            printf("析构函数\n");        }    }private:    char *m_pdata;     // 一指针成员};int main(){    A a;    A b(a);   // 复制对象    return 0;}

在拷贝构造函数中,为 b 对象 new 了一个新的空间,这样 a 和 b 指向的是不同的空间,只是内容一致,但是互不影响。
重复的去开辟空间和释放空间效率是很低的,聪明的地球人决定使用写时拷贝。

写时拷贝

写时拷贝:引入一个计数器,每片不同内容的空间上都再由一个计数器组成,在构造第一个类指向时,计数器初始化为1,之后每次有新的类也指向同一片空间时,计数器加 1 ;在析构时判断该片空间对应计数器是否为1,为1则执行清理工作,大于1则计数器减 1 。如果有需要进行增删等 *** 作时,再拷贝空间完成,有利于提高效率。

class String{public:    String(const char* str = "")        :_str(new char[strlen(str) + 1 + 4])//+1表示字符串后面要放一个'[+++]',+4表示多开辟一个空间存放引用计数    {        _str += 4;//_str指向数据存放区        strcpy(_str, str);        _GetCount() = 1;    }    String(const String& s)        :_str(s._str)    {        _GetCount()++;    }    String& operator=(String& s)    {        if (this != &s)        {            if (--_GetCount() == 0)            {                delete[](_str - 4);            }            ++s._GetCount();            _str = s._str;        }        return *this;    }    ~String()    {        if (--_GetCount() == 0)        {            delete[](_str - 4); // 注意:由于计数器存放在了_str首地址-4的地址上,所以在析构时一定要注意全部释放,避免内存泄漏。        }    }public:    int& _GetCount()    {        return *((int*)_str - 1);    }private:    char* _str;};

相关文章:

C#浅拷贝和深拷贝实例解析

Python中的赋值、浅拷贝、深拷贝介绍 总结

以上是内存溢出为你收集整理的C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝全部内容,希望文章能够帮你解决C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝_C_内存溢出

C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝

C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝,第1张

概述C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝

对于普通的类型来说,拷贝没什么大不了的。

int a = 0;int b = a;

不会出现任何问题。

而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。

浅拷贝

首先来说说我们常遇到的浅拷贝的情况。

#include <stdio.h> class student{public:    student()      // 构造函数,p指向堆中分配的一空间    {        _name = new char(100);        printf("默认构造函数\n");    }    ~student()     // 析构函数,释放动态分配的空间    {        if (_name != NulL)        {            delete _name;            _name = NulL;            printf("析构函数\n");        }    }private:    char * _name;     // 一指针成员};int main(){    student a;    student b(a);   // 复制对象    return 0;}

这段代码乍看之下没什么毛病,通过类的默认构造函数将 a 复制给 b ,但是一旦运行就会程序崩溃。
经过我的刻苦学习与钻研,终于发现其中的问题所在。
由于我的类没有拷贝构造函数,所以student b(a)会调用,编译器自动生成的一个默认拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
浅拷贝:

@H_419_28@

浅拷贝只是拷贝了指针,并没有创建新的空间,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃。

浅拷贝使得 a 和 b 指向同一块内存,任何一方的变动都会影响到另一方。

由于 a 和 b 指向的是同一块内存空间,当 a 释放了后,b 指向的内存空间不复存在,所以会出现内存泄露的情况。

如何避免浅拷贝害人呢?
养成自定义拷贝构造函数的习惯,当显式定义了拷贝构造函数后,编译器就会调用拷贝构造函数了,为了不出现程序崩溃,请使用自定义拷贝构造函数,当然我们自己如果把代码写成了浅拷贝的形式,那也不是不可能的事。

深拷贝
// 使用自定制拷贝构造函数,完成深拷贝!!!class A{public:    A()      // 构造函数,p指向堆中分配的一空间    {        m_pdata = new char(100);        printf("默认构造函数\n");    }    A(const A& r)    // 拷贝构造函数    {        m_pdata = new char(100);    // 为新对象重新动态分配空间        memcpy(m_pdata, r.m_pdata, strlen(r.m_pdata));        printf("copy构造函数\n");    }    ~A()     // 析构函数,释放动态分配的空间    {        if (m_pdata != NulL)        {            delete m_pdata;            printf("析构函数\n");        }    }private:    char *m_pdata;     // 一指针成员};int main(){    A a;    A b(a);   // 复制对象    return 0;}

在拷贝构造函数中,为 b 对象 new 了一个新的空间,这样 a 和 b 指向的是不同的空间,只是内容一致,但是互不影响。
重复的去开辟空间和释放空间效率是很低的,聪明的地球人决定使用写时拷贝。

写时拷贝

写时拷贝:引入一个计数器,每片不同内容的空间上都再由一个计数器组成,在构造第一个类指向时,计数器初始化为1,之后每次有新的类也指向同一片空间时,计数器加 1 ;在析构时判断该片空间对应计数器是否为1,为1则执行清理工作,大于1则计数器减 1 。如果有需要进行增删等 *** 作时,再拷贝空间完成,有利于提高效率。

class String{public:    String(const char* str = "")        :_str(new char[strlen(str) + 1 + 4])//+1表示字符串后面要放一个'',+4表示多开辟一个空间存放引用计数    {        _str += 4;//_str指向数据存放区        strcpy(_str, str);        _GetCount() = 1;    }    String(const String& s)        :_str(s._str)    {        _GetCount()++;    }    String& operator=(String& s)    {        if (this != &s)        {            if (--_GetCount() == 0)            {                delete[](_str - 4);            }            ++s._GetCount();            _str = s._str;        }        return *this;    }    ~String()    {        if (--_GetCount() == 0)        {            delete[](_str - 4); // 注意:由于计数器存放在了_str首地址-4的地址上,所以在析构时一定要注意全部释放,避免内存泄漏。        }    }public:    int& _GetCount()    {        return *((int*)_str - 1);    }private:    char* _str;};

相关文章:

C#浅拷贝和深拷贝实例解析

Python中的赋值、浅拷贝、深拷贝介绍 总结

以上是内存溢出为你收集整理的C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝全部内容,希望文章能够帮你解决C++---浅拷贝、深拷贝、写时拷贝讲解(附代码)浅拷贝深拷贝写时拷贝所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1211372.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存