陷阱重重的C++赋值重载函数operator=

来源:互联网 发布:淘宝主图视频手机拍摄 编辑:程序博客网 时间:2024/06/05 08:23

曾经有C++高手说过:看一个C++程序员功底是否够硬,让他写个赋值重载函数就能看出来了!在我看来,这种说法并不夸张。因为能将operator=函数写好确实需要扎实的基础,其中的陷阱真不少。

  • 陷阱一:不懂规避自我拷贝

先看代码

[cpp] view plain copy
 print?
  1. string& string::operator=(const string& rhs)  
  2. {  
  3.     if (m_pStr != NULL)  
  4.         delete [] m_pStr;  
  5.     m_pStr = new char[....];  
  6.     strcpy(....);  
  7.   
  8.     return *this;  
  9. }  

此代码就是没有规避自我赋值,那么如果进行以下的调用,那么后果很严重。

[cpp] view plain copy
 print?
  1. string myStr("abc");  
  2. myStr = myStr;  

赋值操作中,会先把自己的数据delete掉,然后再strcpy一个空值,程序立马挂了。

所以,在赋值函数开始的时候,需要防止自我复制。写法如下:

[cpp] view plain copy
 print?
  1. string& string::operator=(const string& rhs)  
  2. {  
  3.     // 防止自我赋值  
  4.     if (this == &rhs)  
  5.         return * this;  
  6.   
  7.     ...  
  8. }  
但有些书籍上面使用以下写法,不敢苟同。

[cpp] view plain copy
 print?
  1. string& string::operator=(const string& rhs)  
  2. {  
  3.     // 防止自我赋值  
  4.     if (*this == rhs) // 这只是判断内容是否相同,并不能判定是自我赋值!!!  
  5.         return * this;  
  6.   
  7.     ...  
  8. }  
  • 陷阱二:返回值的类型用啥

在初学者的群体当中,有出现诸如以下几种返回值版本:

[cpp] view plain copy
 print?
  1. // 版本一  
  2. string string::operator=(const string& rhs)  
  3. {  
  4.     ...  
  5.     return * this;  
  6. }  

[cpp] view plain copy
 print?
  1. // 版本二  
  2. const string& string::operator=(const string& rhs)  
  3. {  
  4.     ...  
  5.     return * this;  
  6. }  

[cpp] view plain copy
 print?
  1. // 版本三  
  2. string* string::operator=(const string& rhs)  
  3. {  
  4.     ...  
  5.     return this;  
  6. }  

版本一的缺陷:多了一个临时对象的生成和拷贝,影响程序效率。

版本二的缺陷:非const类型的变量想得到它的连续赋值变得不可能,而且编译器也会报错。

版本三的缺陷:不能保持连续赋值时类型的统一性,违反了编程的惯例。如

[cpp] view plain copy
 print?
  1. // 版本三的缺陷  
  2. string a, b, c;  
  3. *a = b = c; // 必须这样赋值给a,类型不统一!!   
  • 陷阱三:未做深拷贝

任何未做深拷贝的版本都退化为默认版本。

[cpp] view plain copy
 print?
  1. string& string::operator=(const string& rhs)  
  2. {  
  3.     if (this == &rhs) return *this;  
  4.   
  5.     if (m_pStr != NULL)  
  6.         delete [] m_pStr;  
  7.     m_pStr = rhs.m_pStr; // 浅拷贝  
  8.   
  9.     return *this;  
  10. }