浅谈C 对象的拷贝与赋值操作
创始人
2024-08-02 07:10:44
0

我发现一些同事在用C++编写一个类时,知道什么时候需要实现拷贝构造函数赋值操作,但不知道什么时候拷贝构造函数被调用,什么时候赋值操作被调用,甚至把二者混为一谈。

要弄明白这个问题,最简单的做法莫过于写个测试程序试一下。不过那样做也未必是好办法,实验的结果往往导致以偏概全的结论。不如好好想一下,弄清楚其中的原理,再去写程序去验证也不迟。

拷贝构造函数,顾名思义,等于拷贝 + 构造。它肩负着创建新对象的任务,同时还要负责把另外一个对象拷贝过来。比如下面的情况就调用拷贝构造函数:

  1. cstring str = strother; 

赋值操作则只含有拷贝的意思,也就是说对象必须已经存在。比如下面的情况会调用赋值操作。

  1. str = strother; 

不过有的对象是隐式的,由编译器产生的代码创建,比如函数以传值的方式传递一个对象时。由于看不见相关代码,所以不太容易明白。不过我们稍微思考一下,就会想到,既然是根据一个存在的对象拷贝生成新的对象,自然是调用拷贝构造函数了。

两者实现时有什么差别呢?我想有人会说,没有差别。呵,如果没有差别,那么只要实现其中一个就行了,何必要两者都实现呢?不绕圈子了,它们的差别是:

拷贝构造函数对同一个对象来说只会调用一次,而且是在对象构造时调用。此时对象本身还没有构造,无需要去释放自己的一些资源。而赋值操作可能会调用多次,你在拷贝之前要释放自己的一些资源,否则会造成资源泄露。

明白了这些道理之后,我们不防写个测试程序来验证一下我们的想法:

  1. #include   
  2. #include   
  3. #include   
  4. class cstring  
  5. {   
  6. public:  
  7. cstring();  
  8. cstring(const char* pszbuffer);  
  9. ~cstring();  
  10. cstring(const cstring& other);  
  11. const cstring& operator=(const cstring& other);  
  12. private:  
  13. char* m_pszbuffer;;  
  14. };   
  15. cstring::cstring()  
  16. {  
  17. printf("cstring::cstring\n");  
  18. m_pszbuffer = null;  
  19. return;   
  20. }   
  21. cstring::cstring(const char* pszbuffer)  
  22. {  
  23. printf("cstring::cstring(const char* pszbuffer)\n");  
  24. m_pszbuffer = pszbuffer != null ? strdup(pszbuffer) : null;  
  25. return;  
  26. }  
  27. cstring::~cstring()  
  28. {  
  29. printf("%s\n", __func__);  
  30. if(m_pszbuffer != null)  
  31. {  
  32. free(m_pszbuffer);  
  33. m_pszbuffer = null;  
  34. }  
  35. return;  
  36. }  
  37. cstring::cstring(const cstring& other)  
  38. {  
  39. if(this == &other)  
  40. {  
  41. return;  
  42. }  
  43. printf("cstring::cstring(const cstring& other)\n");  
  44. m_pszbuffer = other.m_pszbuffer != null ? strdup(other.m_pszbuffer) : null;  
  45. }  
  46. const cstring& cstring::operator=(const cstring& other)  
  47. {  
  48. printf("const cstring& cstring::operator=(const cstring& other)\n");  
  49. if(this == &other)  
  50. {  
  51. return *this;  
  52. }  
  53.  
  54. if(m_pszbuffer != null)  
  55. {  
  56. free(m_pszbuffer);  
  57. m_pszbuffer = null;  
  58. }  
  59. m_pszbuffer = other.m_pszbuffer != null ? strdup(other.m_pszbuffer) : null;  
  60. return *this;  
  61. }  
  62.  
  63. void test(cstring str)  
  64. {  
  65. cstring str1 = str;  
  66. return;  
  67. }  
  68.  
  69. int main(int argc, char* argv[])  
  70. {  
  71. cstring str;  
  72. cstring str1 = "test";  
  73. cstring str2 = str1;  
  74. str1 = str;  
  75. cstring str3 = str3;  
  76. test(str);  
  77. return 0;  

希望对你有帮助。

【编辑推荐】

  1. C++中static的用法总结
  2. C++内存管理的探讨
  3. C++的输出格式控制技巧分析
  4. C++多态技术的实现和反思
  5. C++中的指针用法汇集

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...