Google C++プログラミング仕様でのレプリケーション構造関数と付与演算子の無効化
Google C++プログラミング仕様では、次の説明があります.
具体的には明らかにされていないが、今日は『More Effective C+』を見て、この問題を考え直した.
コンストラクション関数のコピーを無効にする理由は、次の2つです(以下を含むが、これらに限定されません).
1.時間がかかる
継承階層が深くなるとオブジェクトが大きくなり、浅いレプリケーションを採用すると、速度が速くなりますが、メモリの漏洩や野ポインタの発生などのリスクがあります.深いコピーを採用すると、速度がかなり遅くなります.割り当て演算子も同じです.
2.安全でない
付与演算子を使用する場合は、次の例を考慮します(読みやすいように、関数の定義とクラスの定義を一緒にしました).
次のmain関数を実行するとき:
呼び出されたのはHuman &operator=(const Human &rhs)このレプリケーション演算子.ベースクラスの付与演算子を呼び出すと、コピーされるのはベースクラスの部分だけで、本当の派生クラスの部分はコピーされません.これは私たちの意味に合いません.
付与演算子を虚関数として宣言すると、ベースクラスの
virtual Male &operator= (const Human &rhs).この動作は私たちの意味とは異なり、呼び出しを望んでいます.
virtual Male &operator=(const Male &rhs).これを実現するには実際には可能ですが、一定の時間がかかります.呼び出した関数でdynamic_を使用するcastは、入力されたパラメータの動的タイプがベースクラスであるか派生クラスであるかを知ることができ、正しい付与演算子を選択します.でもdynamic_castの時間効率は本当によくありません.特に継承階層が深くなったときです.
以上のように、タイプを定義するときに、必要でない場合は、付与演算子とレプリケーション構造関数をできるだけ無効にします.代替として、このようなベースクラスを宣言し、そのベースクラスを継承することができます.
cloneでコピーした要素を指すポインタを返すといいです.もっと安全にしたいなら、戻ってきたポインタをauto_に包装してください.ptrタイプまたは他のスマートポインタタイプ.
;
DISALLOW_COPY_AND_ASSIGN。
: ( )。
: ,STL 、 。
:C++ bugs 。
, , ,
。
具体的には明らかにされていないが、今日は『More Effective C+』を見て、この問題を考え直した.
コンストラクション関数のコピーを無効にする理由は、次の2つです(以下を含むが、これらに限定されません).
1.時間がかかる
継承階層が深くなるとオブジェクトが大きくなり、浅いレプリケーションを採用すると、速度が速くなりますが、メモリの漏洩や野ポインタの発生などのリスクがあります.深いコピーを採用すると、速度がかなり遅くなります.割り当て演算子も同じです.
2.安全でない
付与演算子を使用する場合は、次の例を考慮します(読みやすいように、関数の定義とクラスの定義を一緒にしました).
#ifndef _HUMAN_H
#define _HUMAN_H
#include <cstdio>
class Human {
public :
Human &operator=(const Human &rhs){
printf("Human &operator=(const Human &rhs)
");
return *this;
}
};
class Male : public Human{
public :
Male &operator= (const Human &rhs) {
printf("Male &operator= (const Human &rhs)
");
return *this;
}
Male &operator=(const Male &rhs) {
printf("Male &operator=(const Male &rhs)
");
return *this;
}
};
class Female : public Human {
public :
Female &operator= (const Human &rhs) {
printf("Female &operator= (const Human &rhs)
");
return *this;
}
Female &operator=(const Female &rhs) {
printf("Female &operator=(const Female &rhs)
");
return *this;
}
};
#endif // _HUMAN_H
次のmain関数を実行するとき:
int main() {
Human *male1 = new Male();
Human *male2 = new Female();
*male1 = *male2;
return 0;
}
呼び出されたのはHuman &operator=(const Human &rhs)このレプリケーション演算子.ベースクラスの付与演算子を呼び出すと、コピーされるのはベースクラスの部分だけで、本当の派生クラスの部分はコピーされません.これは私たちの意味に合いません.
付与演算子を虚関数として宣言すると、ベースクラスの
virtual Male &operator= (const Human &rhs).この動作は私たちの意味とは異なり、呼び出しを望んでいます.
virtual Male &operator=(const Male &rhs).これを実現するには実際には可能ですが、一定の時間がかかります.呼び出した関数でdynamic_を使用するcastは、入力されたパラメータの動的タイプがベースクラスであるか派生クラスであるかを知ることができ、正しい付与演算子を選択します.でもdynamic_castの時間効率は本当によくありません.特に継承階層が深くなったときです.
以上のように、タイプを定義するときに、必要でない場合は、付与演算子とレプリケーション構造関数をできるだけ無効にします.代替として、このようなベースクラスを宣言し、そのベースクラスを継承することができます.
class NoCopyAndAssign {
public :
NoCopyAnd *clone() const = 0;
private :
NoCopyAndAssign(const NoCopyAndAssign &);
void operator=(const NoCopyAndAssign &);
};
cloneでコピーした要素を指すポインタを返すといいです.もっと安全にしたいなら、戻ってきたポインタをauto_に包装してください.ptrタイプまたは他のスマートポインタタイプ.