C++必知必会之(13)复制操作

来源:互联网 发布:可以货到付款的软件 编辑:程序博客网 时间:2024/06/06 10:54

1、复制构造和复制赋值是两种不同的操作。它们一般被放到一起,同时出现,并且必须兼容:

class Impl;

class Handle  {

    public:

        //.....

        Handle( const Handle & );   //复制构造函数

        Handle &operator = ( const Handle & );    //复制赋值操作符

        void  swap( Handle & );

        //.....

    private:

        Imple *impl_ ;    //指向Handle的实现

};


2、对于一个类X而言,复制构造函数应该被声明为X( const X & ),而复制赋值操作符则应该被声明为X &operator = ( const X & )。


典型的非成员形式的swap实现是很直观的:

template <typename T>

void swap( T &a,  T &b)   {

           T temp(a);          //调用T的复制构造函数

            a = b;         //调用T的复制赋值操作符

            b = temp;    //调用T的复制赋值操作符

}

如果T的实现短小简单,这种方式很好。若是T是一个庞大的类,就会有不小的开销。对于Handle这样的类,一般我们采用交换指向各自实现的指针的方式:

inline void Handle::swap( Handle &that )

     {     std::swap( impl_,  that.impl_ );    }


3、对于复制赋值的这个实现来说,微妙之处在于复制构造的行为必须和复制赋值的行为“兼容”。尽管它们是不同的操作,然而此处存在一个影响深远的惯用假定,就是它们产生的结果不应该有区别:

也就是说,不管写成:

Handle a = ......

Handle b = ......

b = a;   //将a赋给b

还是写成:

Handle a = ......

Handle b(a);     //用a来初始化b

b的结果值和将来的行为都应该没有差别,不管它是通过赋值还是通过初始化而得到那个值的。


4、当使用标准的容器时,这种兼容性尤其重要,因为它们的实现常常用复制构造来代替复制赋值,当然也就期望两种操作产生一致的结果。

一个或许更常见的复制赋值实现具有如下结构:

Handle &Handle::operator = ( const Handle &that )   {

        if( this != &that )   {

             //进行赋值....

          }

        return *this;

}

这种对自身赋值所执行的检查往往是出于正确性的考虑(有时出于效率方面)。更确切地说为了确保赋值表达式的左操作数(this)和右操作数(例如that)具有不同的地址。 



原创粉丝点击