默认拷贝构造函数,浅拷贝,深拷贝

时间:2021-04-26 19:54:09


类定义中,如果未提供自己的拷贝构造函数,则C++提供一个默认拷贝构造函数,就像没有提供构造函数时,
C++提供默认构造函数一样。
C++提供的默认拷贝构造函数工作的方法是:完成一个成员一个成员的拷贝,如果成员是类对象,则调用
其拷贝构造函数或者默认拷贝构造函数。
/*--------------------------------------
在默认拷贝构造函数中,拷贝的策略是逐个成员依次拷贝,但是,一个类可能会拥有资源,如果拷贝构造函数
简单地制作了一个该资源的拷贝,而不对它本身分配,就得面临一个麻烦的局面:两个对象都拥有同一个资源
。当对象析构时,该资源将经历两次资源返还。
下面的程序描述了Person对象被简单拷贝后,面临析构时的困惑。
--------------------------------------------------*/
#include <iostream>
using namespace std;
class Person
{
public:
   Person(char *pN)
   {
    cout <<"Constructing "<<pN<<endl;
    pName=new char (strlen(pN)+1);
    if (pName!=0)
    {
     strcpy(pName,pN);
    }
   }
  
   ~Person()
   {
    cout<<"Destructing "<<pName<<endl;
    pName[0]='/0';
    delete   pName;
  
   }

protected:
   char *pName;
} ;
int main()

Person   p1("Randy");
Person   p2=p1;               //即Person p2 (p1);
}
/*
result is :
Constructing Randy
Destructing Randy
Destructing 
*/

/*---------------------------
程序开始运行时,创建p1对象,p1对象的构造函数从堆中分配空间并赋给数据成员pName,
执行,p2=p1时,因为没有定义拷贝构造函数,于是就调用默认拷贝构造函数,使得p2与p1完全一样,
并没有新分配堆空间给p2, p1与p2的pName都是同一个值。析构p2时,将堆中字符串清成空串,然后
将堆空间返还给系统; 析构p1时,因为这是pName指向的是空串,所以第三行输出中显示的只是Destructing,
当执行 delete pName ; 按道理系统应该报错,但在gcc中没有

创建p2时,对象p1被复制了p2,但资源并未复制,因此,p1和p2指向同一个资源,这称为浅拷贝。
当一个对象创建时,分配了资源,这时,就需要定义自己的拷贝构造函数,使之不但拷贝成员,也拷贝资源
#include <iostream>
using namespace std;
class Person
{
public:
   Person(char *pN)
   {
    cout <<"Constructing "<<pN<<endl;
    pName=new char (strlen(pN)+1);
    if (pName!=0)
    {
     strcpy(pName,pN);
    }
   }
  
Person(Person& p)
{
cout <<"copying "<<p.pName<<"into its own block/n";
pName=new char [sizeof(p.pName)];
if (pName!=0)
   strcpy(pName,p.pName);


   ~Person()
   {
    cout<<"Destructing "<<pName<<endl;
    pName[0]='/0';
    delete   pName;
  
   }

protected:
   char *pName;
} ;
int main()

Person   p1("Randy");
Person   p2=p1;               //即Person p2 (p1);
}

result is :
Constructing Randy
copying Randyinto its own block
Destructing Randy
Destructing Randy

创建p2时,对象p1被复制给了p2,同时资源也作了复制,因此p1和p2指向不同的资源,这称为深拷贝。
堆内存并不是唯一需要拷贝构造函数的资源,但它是最常用的一个。打开文件,占有硬设备(例如打印机
)服务也需要深拷贝。他们也是析构函数必须返还的资源类型。因此一个很好的经验是:
如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。
因为通常对象是自动被析构的,如果需要一个自定义的析构函数,那就意味着有额外资源要在对象被析构之前
释放,此时,对象的拷贝就不是浅拷贝了。
类定义中,如果未提供自己的拷贝构造函数,则C++提供一个默认拷贝构造函数,就像没有提供构造函数时,
C++提供默认构造函数一样。
C++提供的默认拷贝构造函数工作的方法是:完成一个成员一个成员的拷贝,如果成员是类对象,则调用
其拷贝构造函数或者默认拷贝构造函数。
/*--------------------------------------
在默认拷贝构造函数中,拷贝的策略是逐个成员依次拷贝,但是,一个类可能会拥有资源,如果拷贝构造函数
简单地制作了一个该资源的拷贝,而不对它本身分配,就得面临一个麻烦的局面:两个对象都拥有同一个资源
。当对象析构时,该资源将经历两次资源返还。
下面的程序描述了Person对象被简单拷贝后,面临析构时的困惑。
--------------------------------------------------*/
#include <iostream>
using namespace std;
class Person
{
public:
   Person(char *pN)
   {
    cout <<"Constructing "<<pN<<endl;
    pName=new char (strlen(pN)+1);
    if (pName!=0)
    {
     strcpy(pName,pN);
    }
   }
  
   ~Person()
   {
    cout<<"Destructing "<<pName<<endl;
    pName[0]='/0';
    delete   pName;
  
   }

protected:
   char *pName;
} ;
int main()

Person   p1("Randy");
Person   p2=p1;               //即Person p2 (p1);
}
/*
result is :
Constructing Randy
Destructing Randy
Destructing 
*/

/*---------------------------
程序开始运行时,创建p1对象,p1对象的构造函数从堆中分配空间并赋给数据成员pName,
执行,p2=p1时,因为没有定义拷贝构造函数,于是就调用默认拷贝构造函数,使得p2与p1完全一样,
并没有新分配堆空间给p2, p1与p2的pName都是同一个值。析构p2时,将堆中字符串清成空串,然后
将堆空间返还给系统; 析构p1时,因为这是pName指向的是空串,所以第三行输出中显示的只是Destructing,
当执行 delete pName ; 按道理系统应该报错,但在gcc中没有

创建p2时,对象p1被复制了p2,但资源并未复制,因此,p1和p2指向同一个资源,这称为浅拷贝。
当一个对象创建时,分配了资源,这时,就需要定义自己的拷贝构造函数,使之不但拷贝成员,也拷贝资源
#include <iostream>
using namespace std;
class Person
{
public:
   Person(char *pN)
   {
    cout <<"Constructing "<<pN<<endl;
    pName=new char (strlen(pN)+1);
    if (pName!=0)
    {
     strcpy(pName,pN);
    }
   }
  
Person(Person& p)
{
cout <<"copying "<<p.pName<<"into its own block/n";
pName=new char [sizeof(p.pName)];
if (pName!=0)
   strcpy(pName,p.pName);


   ~Person()
   {
    cout<<"Destructing "<<pName<<endl;
    pName[0]='/0';
    delete   pName;
  
   }

protected:
   char *pName;
} ;
int main()

Person   p1("Randy");
Person   p2=p1;               //即Person p2 (p1);
}

result is :
Constructing Randy
copying Randyinto its own block
Destructing Randy
Destructing Randy

创建p2时,对象p1被复制给了p2,同时资源也作了复制,因此p1和p2指向不同的资源,这称为深拷贝。
堆内存并不是唯一需要拷贝构造函数的资源,但它是最常用的一个。打开文件,占有硬设备(例如打印机
)服务也需要深拷贝。他们也是析构函数必须返还的资源类型。因此一个很好的经验是:
如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。
因为通常对象是自动被析构的,如果需要一个自定义的析构函数,那就意味着有额外资源要在对象被析构之前
释放,此时,对象的拷贝就不是浅拷贝了。