戻り値最適化とnoncopyable class
2503 ワード
転載元:http://www.708luo.com/?p=22
今日は出勤します.面白いことがあります.ある同僚にコードを見せてくださいと言われました.このコードはgccでコンパイルできますが、bullseye coverでコンパイルしてカバー率を統計する時に、リンクの段階が間違っていました.
このコードを簡単にします.
私が見てみると、bullseye coverの行為は正しいです.operator+の関数は対象です.引用ではなく、コピー構造の操作があるはずです.
なぜgccはリンクして通ることができますか?第一反応は戻り値の最適化で、今回のコピー構造の操作を最適化しました.
コードを書いてテストしてみましたが、やはり値の最適化の原因に戻ります.しかも最適化オプション-O 0でリターン値を開いて最適化しています.これはちょっと意外です.
もともと私は、NonCopyable classのコピー構造関数はprvateと宣言すればいいと思っていますが、定義が定義されなくてもいいです.とにかく依存するのはアクセス権限のコントロールです.
今回の経験から、NonCopyable classのコピー構造関数を空と定義することは危険なことだと気づきました.メンバー関数によっても呼び出される可能性がありますので、この時にアクセス権限はもう無力です.関数が定義されていないので、提示するしかないです.
間違いに関しては、二つのコンパイラの行為は受け入れられると思います.修正するのはこのコードの編纂方式です.Noncopy classであり、メンバー関数はまた対象事例に戻ります.
しかし、gccは確かに優れています.最適化だけではなく、いくつかの関数の呼び出しを削除したため、必要ではない関数のコードを変更してコンパイルしました.
もともと問題はここで終わりました.gccにはもっと面白い現象があると思います.
NonCopyable classを呼び出して、コピー構造が非メンバ関数である場合、コンパイル段階はアクセス権限のエラーを提示します.しかし、コンパイルを通じて最適化することができますが、この関数は呼び出しされません.アクセス制御をバイパスすれば、例えば、その非メンバー関数をNonCopyable classの友元関数として宣言するなど、完全にコンパイルできます.
次のコード:
実は上のコードはまだ全部書いていません.もしアドド関数を呼んだところがあれば、そこで「Integer:Integer(const Integer&)」is prvateというエラーを報告します.呼び出し先のコードも権限制御を迂回する必要があります.
コードの最適化をコードアクセス権限を確認する前に操作すれば、この問題を回避できると思います.しかし、コンパイラの下の実装はよく分かりません.この調整が可能かどうかは分かりません.
あるいは、私たちはNonCopyable classを書く時、私有のコピー構造関数ではなく、公有のコピー構造関数を宣言しますが、それを定義しません.
このように何か弊害があるか分かりません.間違い以外にヒントが遅くなります.しかし、このようなメリットは、前述の「冤罪」の場合は避けられます.
今日は出勤します.面白いことがあります.ある同僚にコードを見せてくださいと言われました.このコードはgccでコンパイルできますが、bullseye coverでコンパイルしてカバー率を統計する時に、リンクの段階が間違っていました.
このコードを簡単にします.
class Integer
{
public:
Integer(int x=0):_x(x){}
Integer operator+(const Integer& rhs)
{
Integer tmp;
tmp._x += rhs._x;
return tmp;
}
~Integer(){}
private:
Integer(const Integer&);
int _x;
};
私はbullseye coverリンク段階のエラーを見ましたが、つまり「Integer」関数の定義が見つかりません.この関数は「Integer operator+(const Integer&rhs)」で呼び出されました.私が見てみると、bullseye coverの行為は正しいです.operator+の関数は対象です.引用ではなく、コピー構造の操作があるはずです.
なぜgccはリンクして通ることができますか?第一反応は戻り値の最適化で、今回のコピー構造の操作を最適化しました.
コードを書いてテストしてみましたが、やはり値の最適化の原因に戻ります.しかも最適化オプション-O 0でリターン値を開いて最適化しています.これはちょっと意外です.
もともと私は、NonCopyable classのコピー構造関数はprvateと宣言すればいいと思っていますが、定義が定義されなくてもいいです.とにかく依存するのはアクセス権限のコントロールです.
今回の経験から、NonCopyable classのコピー構造関数を空と定義することは危険なことだと気づきました.メンバー関数によっても呼び出される可能性がありますので、この時にアクセス権限はもう無力です.関数が定義されていないので、提示するしかないです.
間違いに関しては、二つのコンパイラの行為は受け入れられると思います.修正するのはこのコードの編纂方式です.Noncopy classであり、メンバー関数はまた対象事例に戻ります.
しかし、gccは確かに優れています.最適化だけではなく、いくつかの関数の呼び出しを削除したため、必要ではない関数のコードを変更してコンパイルしました.
もともと問題はここで終わりました.gccにはもっと面白い現象があると思います.
NonCopyable classを呼び出して、コピー構造が非メンバ関数である場合、コンパイル段階はアクセス権限のエラーを提示します.しかし、コンパイルを通じて最適化することができますが、この関数は呼び出しされません.アクセス制御をバイパスすれば、例えば、その非メンバー関数をNonCopyable classの友元関数として宣言するなど、完全にコンパイルできます.
次のコード:
class Integer
{
public:
friend Integer add(const Integer&,const Integer&);
Integer(int x=0):_x(x){}
~Integer(){}
int get()const{return _x;}
void set(int x){_x=x;}
Integer& operator=(const Integer& rhs)
{
this->_x = rhs._x;
return *this;
}
private:
Integer(const Integer&);
int _x;
};
Integer add(const Integer& lhs,const Integer& rhs)
{
Integer tmp;
tmp.set(lhs.get()+rhs.get());
return tmp;
}
上のコードは、4行目のコメントを外すと、コンパイル段階では「Integer:Integer」「is prvate」というエラーがあります.反対のコメントの4行目はコンパイル、リンクが通ります.実は上のコードはまだ全部書いていません.もしアドド関数を呼んだところがあれば、そこで「Integer:Integer(const Integer&)」is prvateというエラーを報告します.呼び出し先のコードも権限制御を迂回する必要があります.
コードの最適化をコードアクセス権限を確認する前に操作すれば、この問題を回避できると思います.しかし、コンパイラの下の実装はよく分かりません.この調整が可能かどうかは分かりません.
あるいは、私たちはNonCopyable classを書く時、私有のコピー構造関数ではなく、公有のコピー構造関数を宣言しますが、それを定義しません.
このように何か弊害があるか分かりません.間違い以外にヒントが遅くなります.しかし、このようなメリットは、前述の「冤罪」の場合は避けられます.