C++でオブジェクトのコピーを明示的にする
C++の中のオブジェクトのコピーは一般的にコピーコンストラクタを使用しているので、オブジェクトのコピーの多くは暗黙的であり、コピーコンストラクタを使用する暗黙的なコピーは便利であるが、コンパイラは不要なコピーを識別することができない.私たち人間はこれらの不要なコピーを識別することができ、関数の原型を書くときに加算を忘れるよりも、このような不要なコピーを引き起こすことができる.
この場合、コピーコンストラクション関数と付与関数(privateとして宣言)を無効にし、次のような明示的なコピー関数を提供できます.
この方法は確かにworkできますが、不自然に見えます.例えば、
しかし、C++98規格では、関数が非Primitiveの値オブジェクトを返す場合、このオブジェクトは非const参照にbindされませんが、変更できます.
私たちは標準的なこの特徴を利用することができます.
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を呼び出すことができます)......
すると、次のことは簡単に・・・
この場合、コピーコンストラクション関数と付与関数(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を呼び出すことができます)......
すると、次のことは簡単に・・・