Thinking again in C++(二)自赋值是非公断

原创 2003年02月18日 08:50:00

    爱死Thinking in系列了,所以起了这个名字。本文的思想也部分来至于这套书,或参照对比,或深入挖掘,或补益拾慧,或有感而发,既包括Thinking in C++,甚至也包括Thinking in Java。

                          Thinking again in C++(二)自赋值是非公断

    关键字:C++,自赋值,自复制,赋值,assign,assignment,复制,拷贝,copy

    1.需要考虑的自赋值。当类包含指针或引用成员时应注意检查。
      class String
      {
      private:
            char * pc_Buffer;
      public:
            String & operator=(const String & strR);
            String & operator+=(const String & strR);
            //...
      };
    (1)类内部:对称赋值运算符、接受自身类型或自身基类类型参数的成员函数,有时候还要考虑+=系列运算符。
      String & String::operator=(const String & strR)
      {
            if (this==&strR)      //[1]
                  return *this;
            delete [] pc_Buffer;      //[2]
            pc_Buffer=new char[strlen(strR.pc_Buffer)+1];//[3]
            //...
      }
    [1]中的判断是必须的。如果this==&strR,[2]将本身删除,[3]就会使用“悬挂指针”。
    下面operator+=()的实现隐藏着错误。
      String & String::operator+=(const String & strR)
      {
            int iLengthNew=strlen(pc_Buffer)+strlen(strR.pc_Buffer);
            char * pcBufferNew=new char[iLengthNew+1];
            strcpy(pcBufferNew,pc_Buffer);
            delete [] pc_Buffer;                  //[4]
            strcat(pcBufferNew,strR.pc_Buffer);      //[5]
            pc_Buffer=pcBufferNew;
            return *this;
      }
    如果this==&strR,[4]将本身删除,[5]就会使用“悬挂指针”。正确的做法不必使用判断语句,只需调换[4][5]两条语句的顺序。
    (2)类外部(包括友元):接受多个同一类型参数或多个有继承关系的类型参数的函数。
      class CDerive : public CBase{};
      void f(CBase & b1,CBase & b2);
      void g(CBase & b,CDerive & d);
      CBase bSame;
      CDerive dSame;
      f(bSame,bSame);            //[1]
      f(dSame,dSame);            //[2]
      g(dSame,dSame);            //[3]
    [1][2][3]都出现了自赋值,所以f()、g()的设计中都要有所考虑。

    2.不可能出现自赋值。
    (1)拷贝构造器:因为正在构造的对象还未完全生成,而传递给构造器的实参对象是已构造完毕的对象,这两者绝不可能是同一对象。
    (2)非对称赋值运算符:即使形参类型是自身的基类。若D是B的派生类,无论是否重载了对称赋值运算符,D类对象之间的赋值行为都不会调用D::operator=(const B & b)。
      class CDerive : public CBase
      {
      public:
            operator=(const CBase & b);      //不用考虑this和b之间的自赋值
            void f(const CBase & b);      //需要考虑this和b之间的自赋值
      };
      CDerive dSame;
      dSame=dSame;            //[1]
      dSame.f(dSame);            //[2]
    语句[1]中,编译器不会把dSame上溯造型为CBase,而是调用缺省或自定义的D::operator=(const D & d)。只有等式左边确为D,右边确为B,才调用D::operator=(const B & b),这时不可能出现自赋值。相反,语句[2]中,编译器会把dSame上溯造型为CBase,所以f()需要考虑自赋值。

    3.不是自赋值的赋值。仅仅内容相同的赋值不是自赋值。
      CTest a,b,same;
      a=same;
      b=same;
      a=b;      //[1]
    [1]不是自赋值,不会出问题,不需要检查,而且内容相同无法直接用地址来检查。

    4.不应该检查的自赋值。
    strcpy(char * strDest,const char * strSrc);中,当strDest==strSrc时,是自赋值,但并不会出错。
    发现自赋值直接返回,这种特定情况下,也许能提高函数效率10倍,但绝大多数没有出现自赋值时都多了一个条件判断,可能降低函数效率10%,最后综合计算加权平均效率可能还是降低了。这取决于自赋值出现的概率。
    设不判断自赋值,函数执行时间为1;若检查自赋值,设出现自赋值的概率为x,直接返回函数执行时间为0.1,不出现自赋值,多了一个条件判断函数执行时间为1.1,那么如果要求加权平均效率不降低:
      0.1x+1.1(1-x)<1
    解之,得:x>0.1。也就是说自赋值出现的概率必须大于10%,这在实际代码中可能吗?

自赋值是非公断

爱死Thinking in系列了,所以起了这个名字。本文的思想也部分来至于这套书,或参照对比,或深入挖掘,或补益拾慧,或有感而发,既包括Thinking in C++,甚至也包括Thinking in...
  • jaminwm
  • jaminwm
  • 2004年08月31日 19:03
  • 1572

C++的自赋值问题

再用到操作符重载的时候,注意到了这个问题 如果不进行自我赋值检查。就有可能出现一种情况。那是灾难性的。举例说。你在拆房子。如果你不先看看自己是否在房子里就直接拆了。那会是怎么样呢??想想就知道。...
  • OutManLee
  • OutManLee
  • 2012年03月13日 18:59
  • 1565

C++ 重载运算符“=”检测自赋值

重载赋值运算符 赋值运算符可能是最容易令人迷惑的一个,所以,重载它必须十分的小心。 1. 值运算符仅能重载为成员函数。  C++不允许赋值运算符被重载为全局形式,这是因为如果可以写出...
  • wo17fang
  • wo17fang
  • 2014年08月12日 10:40
  • 638

Thinking In C++中文版

----------------------- Page 1----------------------- 下载                       第1章  对象的演化     计算机革命起...
  • liu_hang_yu
  • liu_hang_yu
  • 2011年05月17日 07:11
  • 4080

从《thinking in C++》被迫转到《C++ Primer》第一天

今天啃《thinking in C++》有种不能继续下去的感觉,一方面我一看书就停不下来,难懂+没有休息容易困,所以看的速度并不快。另外感觉里边有很多内容在建立在你了解其使用的基础上的理论提升,所以我...
  • lihb018
  • lihb018
  • 2014年09月21日 22:36
  • 3852

Thinking in C++ (1-5)

 创建和删除对象从技术上讲,OOP的主要领域是抽象数据类型,继承,以及多态,但是其他领域一样很重要,在这一节中我们简单的介绍一下这些内容。尤其重要的是对象创建和删除的方法。对象的数据是保存在哪里的,又...
  • tiandejian
  • tiandejian
  • 2006年07月17日 10:48
  • 1314

《Thinking in C++》练习题答案——3-3

#include #include using namespace std;int main(){        string words;        int a;        bool qui...
  • cgtezhao
  • cgtezhao
  • 2007年05月20日 18:09
  • 423

为什么赋值运算符要防止自身赋值

为什么赋值运算符要防止自身赋值呢?? 如果类里面含有指针指向动态分配的资源的话,那么自身赋值就可能出错 有可能导致把自己给释放了 如下面: #include #i...
  • u012501262
  • u012501262
  • 2014年03月29日 15:41
  • 775

《Thinking in C++》练习题答案——2-1

#include using namespace std;int main(){ cout } 
  • cgtezhao
  • cgtezhao
  • 2007年05月13日 16:26
  • 362

《thinking in c++》与我的翻译 (一)

声明:我的翻译不求意思一样,只求你学习编程的时候能够容易理解。因此,我可能会把其中的某些语句隔过去,把某些词换一种描述。 1:Introduction to Objects The genesis...
  • a951084634
  • a951084634
  • 2011年11月17日 22:16
  • 1261
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Thinking again in C++(二)自赋值是非公断
举报原因:
原因补充:

(最多只允许输入30个字)