您的位置: 网界网 > 网络学院-技术开发 > 正文

关于C++默认拷贝构造函数产生的问题的讨论

2014年06月19日 20:34:49 | 作者:佚名 | 来源:51CTO | 查看本文手机版

摘要:对于拷贝构造函数,我前面的博文有提起过,不过,有的时候,浅拷贝和深拷贝真的很难理解,所以,我们再进行关于拷贝构造函数的一些讨论。   大家都整到拷贝构造函数分为浅拷贝和深拷贝,系统默认的拷贝构造函数是浅拷贝...

标签
C++构造函数

对于拷贝构造函数,我前面的博文有提起过,不过,有的时候,浅拷贝和深拷贝真的很难理解,所以,我们再进行关于拷贝构造函数的一些讨论。  

大家都整到拷贝构造函数分为浅拷贝深拷贝,系统默认的拷贝构造函数是浅拷贝。

默认拷贝构造函数以内存拷贝的方式将旧有对象的内存空间拷贝到新对象的内存空间。

如果类中有指针类型的类型的时候,默认拷贝构造函数只能复制指针属性的值,而不能复制指针属性所指向的内存,此时,如果我们自己不显式定义拷贝构造函数,那么我们在编程的时候,可能会出现很诡异的问题。

显式定义拷贝构造函数来完成指针属性等需要特殊处理的属性的拷贝工作。

The Number one :  我们先来看浅拷贝带来的问题

---------------------我是分割线------------------------

  1. # include    
  2. using namespace std;   
  3.     
  4. class Car   
  5. {   
  6. private:   
  7.     char*  brand;   
  8.     float  price;   
  9. public:   
  10.     Car(const char* sz, float p)          
  11.     {   
  12.         //构造函数中为brand分配内存   
  13.         brand = new char[strlen(sz) 1];   
  14.         strcpy(brand, sz);   
  15.     }   
  16.     ~Car   
  17.     {   
  18.         //析构函数中释放申请的内存   
  19.         delete[] brand;   
  20.         cout << " Clear is over ! " << endl;           
  21.     }   
  22.     void just_print()   
  23.     {   
  24.         cout << "brand : " << brand << endl;   
  25.         cout << "price : " << price << endl;   
  26.     }   
  27. };   
  28.     
  29. int main(void)   
  30. {   
  31.     Car car_one("BMW",120);   
  32.     car_one.just_print();   
  33.     //调用默认的拷贝构造函数   
  34.     Car car_two(comp_one);   
  35.     car_two.print();   
  36.     
  37.     return 0;   

----------------------------------------------------------------------------  

这个程序运行失败,代码分析:

1、car_two(car_one)等价于

       car_two.brand = car_one.brand;

       car_two.price  = car_one.price;

2、经过赋值操作后,两个对象中的指针指向的是同一块动态内存,当car_one和car_two撤销时,其释放函数都要释放同一块动态内存内存,可是,两个对象撤销有先有后,一旦一个对象被撤销,另一个对象的brand指针变速"野指针",使用该指针再次释放同一块动态内存会引发内存错误。

不仅仅是重复释放内存的问题,还会出现其他问题:

-------------------------------------------------------------------------------

  1. int main(void)   
  2. {   
  3.     Car car_one("Dell", 7000);   
  4.         
  5.     if(true)   
  6.     {   
  7.         car car_two(car_one);   
  8.         car_two.print();   
  9.     }   
  10.     //car_one.brand指向的动态内存此时已经被释放   
  11.     car_one.print();   
  12.         
  13.     return 0;   

-------------------------------------------------------------------------------------------

由于car_two是在if结构中定义的局部对象,因此if结构退出时,car_two被撤销(+微信关注网络世界),系统自动调用其析构函数,释放了car_two.brand所指向的动态内存,由于car_one和car_two值相同,此时car_one.brand已无所指,成了野指针,此时,对该指针的读写操作都会引发无法预料的错误。

----------------------------------------------------------------------------

此时,我们就需要自己来定义拷贝构造函数:

----------------------------------------------------------------------------

  1. //显式定义构造函数   
  2. # include    
  3. # include    
  4. using namespace std;   
  5.     
  6. class Car   
  7. {   
  8. private:   
  9.     char*    brand;   
  10.     float    price;   
  11. public:   
  12.     Car(const char*  sz, float  p)       
  13.     {   
  14.     brand = new char[strlen(sz) 1];   
  15.         strcpy(brand, sz);   
  16.         price = p;           
  17.     }   
  18.     //自定义拷贝构造函数   
  19.     Car(const  Car&  cp)   
  20.     {   
  21.     //重新为brand开辟与cp.brand同等大小的内存空间   
  22.     brand = new char[strlen(cp.brand)   1];   
  23.         //   
  24.         strcpy(brand, cp.brand);   
  25.         price = cp.price;           
  26.     }   
  27.     ~Car()   
  28.     {   
  29.     delete[]  brand;   
  30.         cout << "clear over " <
  31.     }   
  32.         
  33.     void print()   
  34.     {   
  35.     cout << "brand " << endl;   
  36.         cout << "price " << endl;    
  37.     }       
  38. };   
  39.     
  40. int main(void)   
  41. {   
  42.     Car car_one("Dell", 8999);   
  43.     car_one.print();   
  44.     //   
  45.     Car car_two(car_one);   
  46.     car_two.print();   
  47.     //没有采用brand = cp.brand 这种直接直接赋值,而是重新申请动态内存,使用   
  48.     //库函数strcpy实现了字符串的复制   
  49.     //car_one.brand和car_two.brand指向两块不同的内存,避免了错误   
  50.              
  51.     return 0;   

------------------------------------------------------------------------------------------

最后提一点,自定义的拷贝构造函数,最好也重载operator=运算符!

-----------------------------------------------------------------------------------------

51cto博客:http://liam2199.blog.51cto.com/2879872/1417892

[责任编辑:孙可 sun_ke@cnw.com.cn]