C++里面的深拷贝和浅拷贝

来源:互联网 发布:泰国蛇毒洗面奶知乎 编辑:程序博客网 时间:2024/06/06 00:31






//拷贝有两种:深拷贝和浅拷贝




//1.结构体中的深拷贝和浅拷贝




/*
  浅拷贝:编译器仅仅拷贝了结构体的值,而没有创建新的内存空间,而是共享同一块内存空间
。当结构体成员中含有buf的时候,拷贝之后释放内存就不会出现问题,但是如果结构体中含有指针变量时,
  编译器就只会拷贝指针变量,而对应
  的,内存空间却不会缺,不再多分配。

深拷贝:
    编译器会为拷贝的对象分配一定的内存空间


#include <iostream>using namespace std;/* struct Teacher{  string name;  int  age;}Teacher;int main(){   struct Teacher t1={"cang",18};   struct Teacher t2={"li",20};  t2=t1;//浅拷贝,没有为t2创建内存空间  cout<<"age is:"<<t2.age<<"name is:"<<t2.name<<endl;return 0;}*/


//上面的结构体可以直接使用等于号进行赋值操作;/*#include <iostream>#include <stdio.h>using namespace std; struct Teacher{  int  id;  char sex; const char *p;}Teacher;int main(){   struct Teacher t1, t2;   //const 修饰加上,因为const 存储在常量区,不能被修改,通过指针修改比较危险   //所以通过前面加上const之后,警告消失   const char *str ="i am string";   t1.id = 345;   t1.sex = 'y';   //const 修饰的变量只能用const修饰的变量来接收   t1.p = str;   t2=t1;    printf("t2: %d,%c,%s\n",t2.id,t2.sex,t2.p);   //此处打印出来的丢值都是一样的,说明并没有将内容复制一块给新指针,   //只是让新的指针指向原来的那个地址,这就相当于,指针在这个过程中只赋值了地值   //而不是内容   printf("s1 ptr:%p,p2 ptr:%p\n",t1.p,t2.p);    //这里没有进行运算符重载,所以会出现operator+();   cout<<"t2:"<<t2.id<<t2.sex,t2.p<<endl;   cout<<"t1.p:"<<(void *)t1.p<<"t2.p"<<(void *)t2.p<<endl;   return 0;}*/


//上面函数的原理:
/*在拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数
 缺省的拷贝构造函数对基本类型的成员变量,按字节赋值,对于类型的成员变量,调用其相应类型的拷贝构造函数
 。但是注意缺省的构造函数确实这样的:缺省拷贝构造函数在拷贝过程中是按自己复制的,对于指针变量只赋值指针本身,
 而不赋值指针所指项目标======浅拷贝
 
 这就是问题产生的原因:  ***********浅拷贝出现了****************************************************

 在对对象进行赋值之后,事实上S1,S2的成员都指向同一块内存空间(内存共享)在t1析构时,delete了成员指针所指向的内存空间
 而t2被析构时同样指向了(此时这个指针已经变成了野指针)并且要释放这篇已经被t1析构了的内存空间。在同一片空间出现两次释放
 自然会出现段错误;
 由于内存共享,只要一个子对象改变了其中的值,另一个对象的值也就改变了。

 怎么实现深拷贝:
    自定义拷贝构造函数


 */

#include <iostream>#include <stdio.h>#include <string.h>using namespace std; struct Teacher{  int  id;  char sex;  char *p;  //自定义拷贝构造函数,实现深拷贝 Teacher operator=(Teacher & tec) {    id  = tec.id;sex = tec.sex;p = new char(strlen(tec.p)+1);strcpy(this->p,tec.p);return *this;   }};//相当于重载operator= 方法,这样还是运行,结果就变了int main(){   struct Teacher t1, t2;   //const 修饰加上,因为const 存储在常量区,不能被修改,通过指针修改比较危险   //所以通过前面加上const之后,警告消失   char *str ="i am string";   t1.id = 345;   t1.sex = 'f';   //const 修饰的变量只能用const修饰的变量来接收   t1.p = (char *)str;   t2=t1;    printf("t2: %d,%c,%s\n",t2.id,t2.sex,t2.p);   printf("s1 ptr stress:%p,p2 ptr stress:%p\n",t1.p,t2.p);   printf("s1 ptr:%s,p2 ptr:%s\n",t1.p,t2.p);        return 0;}



//类和上面的结构体一致,其实可以将结构体看成一个类来处理,结构体可以有自己的构造,析构,重载运算符,
//可以简单的认为结构体是类的一种形式。


//拷贝函数有两种:深拷贝 浅拷贝

//当出现类的等号赋值时,会调用拷贝函数,在未定义的显示拷贝构造函数的情况下,系统会调用默认的拷贝函数----浅拷贝
//能够完成成员的复制

//当成员数据中没有指针时,浅拷贝是可以的,但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针指向同一个地址,
//当对象快结束的时候,会调用两次析构,而导致指针悬挂现象。所以,这时必须采用深拷贝,深拷贝与前拷贝的不同在于
//深拷贝会在堆内存中申请空间来存储数据,从而也就结局了指针悬挂的问题。简而言之,当数据成员中有指针的时候,必须要用
//深拷贝。
//建议:
//  我们在定义类或者是结构体的时候,最后都重写拷贝构造函数,避免浅拷贝;这类不宜发现但后果严重的错误产生。









































*/

原创粉丝点击