swap 到底做了什么,它该如何用

swap 到底做了什么,它该如何用

swap 到底做了什么
swap 交换两个内置数据类型的变量时,直接交换。
swap 交换自定义类型对象时,如果里面没有成员指针,直接交换各个对应成员。
如果自定义类型中有指针成员,则是交换两个指针的值,但是指针的指向的值得不到交换。
正是由于这个原因,可以用 swap 进行重载 operator = 时避免自赋值情况,而是生产一个临时对象,然后与本对象 swap 即可。

关于重载 operator = 自赋值的情况,更详细内容可以查看《Effective C++》
实验程序:

  1  #include  < iostream >
  2  using   namespace  std;
  3 
  4  class  Str
  5  {
  6  private :
  7       char *  s_;
  8  public :
  9      Str( const   char *  s  =   "" )
 10      {
 11          s_  =   new   char [strlen(s)  +   1 ];
 12           if  (s_  ==   0 )
 13          {
 14              cout  <<   " test "   <<  endl;
 15              exit( 1 );
 16          }
 17          strcpy(s_, s);
 18      }
 19       //  定义拷贝构造函数,这里会被用于 operator =,swap
 20      Str( const  Str &  rhs)
 21      {
 22          s_  =   new   char [strlen(rhs.s_)  +   1 ];
 23           if  (s_  ==   0 )
 24          {
 25              cout  <<   " test "   <<  endl;
 26              exit( 1 );
 27          }
 28          strcpy(s_, rhs.s_);
 29      }
 30       ~ Str()
 31      {
 32          clear();
 33      }
 34       /// / 常规的 operator = 重载实现方式,必须检查自赋值
 35       /// / 因为如果不自赋值检验,对于自赋值现象如果不调用 clear,则 s_ 在 new 之后就改变,rhs 也改变,原来的丢失,后来的也不是合法内容
 36       /// / 如果调用 clear,不会内存泄露,但是 rhs 的内容被释放掉,rhs 的内容也不是合法内容。
 37       /// / 如果检验自赋值,而没有 clear,原来 *this 的那块内存会被丢失,造成内存泄露。
 38       // Str& operator = (const Str& rhs)
 39       // {
 40       //     if (this != &rhs)
 41       //     {
 42       //         clear();
 43       //         s_ = new char[strlen(rhs.s_) + 1];
 44       //         if (s_ == 0)
 45       //         {
 46       //             exit(1);
 47       //         }
 48       //         strcpy(s_, rhs.s_);
 49       //     }
 50       //     return *this;
 51       // }
 52 
 53       //  改进的 operator,先用一个 temp 保持 rhs,然后 swap
 54       //  这种方式不怕自赋值,因为如果是自赋值,也有一个备份 temp,操作值相同的两个对象 *this 和 temp,直接交换不会影响结果
 55       //  如果不是自赋值,不是交换 *this 和 rhs,而是交换 *this 和 rhs 的一个复制品 temp,最终 *this 得到的值就是 rhs 的一个副本,完成赋值
 56       //  这种方式不用检验自赋值,所以可以省去每次调用时的自赋值检验,在基本上不会遇到自赋值检验的情况下,这种方法可以省去很多误用的检验
 57       //  但是它会每次生成一个副本,这样做的效率与原来的非自赋值一样,而且还需要一个 swap,但是这种方式是异常安全的,用对象来管理资源,资源分配即初始化
 58      Str &   operator   =  ( const  Str &  rhs)
 59      {
 60          cout  <<   " test "   <<  endl;
 61          Str temp(rhs);
 62           //  swap(*this, temp);
 63           //  这里会引起递归调用,因为 operator = 调用 swap,swap 内部又调用 operator = ,一直递归下去,直到栈溢出
 64          swap(s_, temp.s_);
 65           //  Effective C++ 中提到,可以定义一个成员函数 swap,用于交换两个对象对应的数据成员。这样可以防止无限递归。
 66           //  另一种好的方式是除定义一个成员函数 swap 外,传参类型为 值类型 T,这样就可以直接交换返回。
 67           //  这些方法的前提都是要有定义拷贝构造函数的。
 68           return   * this ;
 69      }
 70 
 71       void  clear()
 72      {
 73          delete [] s_;
 74      }
 75       void  foo()
 76      {
 77          cout  <<  s_  <<  endl;
 78      }
 79  };
 80 
 81  int  main()
 82  {
 83       int  a  =   3 , b  =   5 ;
 84      swap(a, b);
 85      cout  <<  a  <<  endl;
 86      cout  <<  b  <<  endl;
 87 
 88      Str s1( " abc " );
 89      Str s2( " xyz " );
 90      s1.foo();
 91      s2.foo();
 92 
 93      swap(s1, s2);
 94       //  这里输出两个 test,我们得知,有两个赋值操作
 95       //  可以推测 swap 的内部实现是 T t(s2), s2 = s1, s1 = t;
 96      s1.foo();
 97      s2.foo();
 98 
 99      s2  =  s1;
100      s1.foo();
101      s2.foo();
102 
103       return   0 ;
104  }


你可能感兴趣的:(swap 到底做了什么,它该如何用)