关于平常的范例来讲,拷贝没什么大不了的。
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)
会挪用,编译器自动生成的一个默许拷贝组织函数,该组织函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
浅拷贝:
浅拷贝只是拷贝了指针,并没有建立新的空间,使得两个指针指向统一个地点,如许在对象块完毕,挪用函数析构的时,会形成统一份资本析构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示意字符串背面要放一个'\0',+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++---浅拷贝、深拷贝、写时拷贝解说(附代码)的细致内容,更多请关注ki4网别的相干文章!