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

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

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

先看代码

  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. return * this;
  8. }

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

  1. string myStr("abc");
  2. myStr = myStr;

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

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

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

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

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

  1. // 版本一
  2. string string:: operator=( const string& rhs)
  3. {
  4. ...
  5. return * this;
  6. }

  1. // 版本二
  2. const string& string:: operator=( const string& rhs)
  3. {
  4. ...
  5. return * this;
  6. }

  1. // 版本三
  2. string* string:: operator=( const string& rhs)
  3. {
  4. ...
  5. return this;
  6. }

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

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

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

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

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

  1. string& string:: operator=( const string& rhs)
  2. {
  3. if ( this == &rhs) return * this;
  4. if (m_pStr != NULL)
  5. delete [] m_pStr;
  6. m_pStr = rhs.m_pStr; // 浅拷贝
  7. return * this;

猜你喜欢

转载自blog.csdn.net/u010248077/article/details/80951639