C++ 的浅拷贝和深拷贝(结构体)
拷贝有两种:深拷贝,浅拷贝
浅拷贝:拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标
(1)结构体中不存在指针成员变量时
1 typedef struct { 2 char name[64]; 3 int age; 4 }Person; 5 6 void test005(){ 7 8 Person stu1 = { "aaa", 18 }; 9 Person stu2; 10 stu2 = stu1; 11 printf("%s,%d ", stu2.name, stu2.age); 12 } 13 14 int main(){ 15 test005(); 16 system("pause"); 17 return 0; 18 }
(2)结构体中存在指针成员变量时
1 typedef struct{ 2 char *name; 3 int age; 4 } Tea; 5 6 void test006(){ 7 Tea teacher1, teacher2; 8 teacher1.name = malloc(sizeof(char)* 64); 9 memset(teacher1.name, 0, 64); 10 strcpy(teacher1.name, "aaaa"); 11 teacher1.age = 18; 12 13 14 teacher2.name = malloc(sizeof(char)* 128); 15 memset(teacher2.name, 0, 128); 16 strcpy(teacher2.name, "bbbb"); 17 teacher2.age = 20; 18 19 //结构体赋值 20 teacher1 = teacher2; 21 22 printf("%s, %d ", teacher2.name, teacher2.age); 23 24 if (NULL != teacher1.name){ 25 free(teacher1.name); 26 teacher1.name = NULL; 27 } 28 if (NULL != teacher2.name){ 29 free(teacher2.name); 30 teacher2.name = NULL; 31 } 32 } 33 34 int main(){ 35 test006(); 36 system("pause"); 37 return 0; 38 }
运行该结构体赋值,出现报错:
浅拷贝存在的问题:当出现类的等号赋值时,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次free函数,此时teacher2已经是野指针,指向的内存空间已经被释放掉,再次free会报错;另外,一片空间被两个不同的子对象共享了,只要其中的一个子对象改变了其中的值,那另一个对象的值也跟着改变了所以,这时,必须采用深拷贝。
深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。
(3)上述代码的改进
解决办法:释放掉被赋值指针变量的旧指向内存,重新对其开辟新内存存放,主要是为了使两个结构体中name指针地址不同,但是指向的内容一致。
1 void test006(){ 2 Tea teacher1, teacher2; 3 teacher1.name = malloc(sizeof(char)* 64); 4 memset(teacher1.name, 0, 64); 5 strcpy(teacher1.name, "aaaa"); 6 teacher1.age = 18; 7 8 9 teacher2.name = malloc(sizeof(char)* 128); 10 memset(teacher2.name, 0, 128); 11 strcpy(teacher2.name, "bbbb"); 12 teacher2.age = 20; 13 14 //结构体赋值 15 //teacher1 = teacher2; 16 //----------------------------------------------- 17 if (teacher1.name != NULL){ 18 free(teacher1.name); 19 teacher1.name = NULL; 20 } 21 teacher1.name = malloc(strlen(teacher2.name) + 1); 22 strcpy(teacher1.name, teacher2.name); 23 //----------------------------------------------- 24 printf("%s, %d ", teacher1.name, teacher1.age); 25 26 if (NULL != teacher1.name){ 27 free(teacher1.name); 28 teacher1.name = NULL; 29 } 30 if (NULL != teacher2.name){ 31 free(teacher2.name); 32 teacher2.name = NULL; 33 } 34 }
建议:
我们在定义类或者结构体,这些结构的时候,最后都重写拷贝函数,避免浅拷贝这类不易发现但后果严重的错误产生