C++でオブジェクトのコピーを明示的にする


C++の中のオブジェクトのコピーは一般的にコピーコンストラクタを使用しているので、オブジェクトのコピーの多くは暗黙的であり、コピーコンストラクタを使用する暗黙的なコピーは便利であるが、コンパイラは不要なコピーを識別することができない.私たち人間はこれらの不要なコピーを識別することができ、関数の原型を書くときに加算を忘れるよりも、このような不要なコピーを引き起こすことができる.
この場合、コピーコンストラクション関数と付与関数(privateとして宣言)を無効にし、次のような明示的なコピー関数を提供できます.
class HeavyObject {
    HeavyObject(const HeavyObject&);
    HeavyObject& operator=(const HeavyObject&);
public:
    void clone_to(HeavyObject& dest) const;
    // more...
};

この方法は確かにworkできますが、不自然に見えます.例えば、
HeavyObject x, y;
    // ...
    y.clone_to(x); // copy y to x
//             :
    x = y.clone();
x = y.clone(); 形式的には自然ですが、実現は容易ではありません(C++11で実現するには容易にし、xに&&を受け入れさせます).
しかし、C++98規格では、関数が非Primitiveの値オブジェクトを返す場合、このオブジェクトは非const参照にbindされませんが、変更できます.
私たちは標準的なこの特徴を利用することができます.
template<class T> struct Ref2 : T {};
template<class T> struct Ref1 {
//        ,Ref1      ,       Ref1&    
    T val;  
    Ref1(const T& y) : val(y) {}  
    operator Ref2<T>&() // this is a non-const member function  
    { return static_cast<Ref2<T>&>(val); }  
};
class HeavyObject {  
    friend struct Ref1<HeavyObject>; // for Ref1 accessing the private copy-cons  
    HeavyObject(const HeavyObject&);
    HeavyObject& operator=(const HeavyObject&);  
public:
    HeavyObject() {}
    void swap(HeavyObject& y) { /*non-throw*/ }  
    void operator=(Ref2<HeavyObject>& y) {  
       // prohibit chained assign  
       this->swap(y); // y is the object created by clone  
    }  
    Ref1<HeavyObject> clone() const {  
        // copy-cons is private and has implementation  
        // assume return value optimization is enabled  
        return Ref1<HeavyObject>(*this);  
    }  
    // more...  
};  

x=y.clone()を実行すると、cloneはRef 1(const HeavyObject&y)を呼び出して一時オブジェクトを作成し、値で返します.このオブジェクトはnon-const referenceにbindできませんが、変更できます.
次にオブジェクトが渡されます HeavyObject::operator=ですが、このoperator=はRef 2&またはconst HeavyObject&のみを受け入れるため、コンパイラはuser defined type conversionを呼び出す必要があります.ここで、Ref 1::operator Ref 2&、この関数はnon-constで、呼び出すことができます.(前に述べたように、non-const referenceにbindすることはできませんが、変更することができ、non-const member functionを呼び出すことができます)......
すると、次のことは簡単に・・・