shared_ptr は使いづらい ― 2012年04月15日 11時57分39秒
一番多かったのが、shared_ptr 型を直接関数に渡す、性能的なバグ。
void function( shared_ptr< Object > obj )
の様な形で渡すと、関数が呼ばれる度に shared_ptr のオブジェクトが生成され、参照回数が更新される。
void function( const shared_ptr< Object >& obj )
何も余計なことをしなくても、const 参照で充分な関数がほとんど。こちらに変えるだけで、関数呼び出しの余計な負荷が押さえられる。
そして、更にこの様な関数を査読を重ねると、何も shared_ptr を取る必要のない関数がほとんどだった。関数内部で、複製したりするわけでもなく、只単に値を参照したり、内部状態を変えているだけ。shared_ptr を取る意味もなく、むしろ shared_ptr にしない方が、余計な制限が減る。shared_ptr を受け取る関数を呼ぶために、わざわざ shared_ptr を生成すると言う本末転倒な、設計のバグも多数。
void function( Object& obj )
にするだけで、余計な関数がなくなった。
そして一番難解なのが、内部保有する shared_ptr を返す const 関数。一部簡略化した例を以下にあげる。
class AddressBook
{
std::map< std::string, shared_ptr< std::string > toAddress;
public:
shared_ptr< std::string > find( const std::string& name ) const
{
std::map< std::string, shared_ptr< std::string >::iterator itr =
toAddress.find( name );
if( itr != toAddress.end() )
return itr->second;
throw std::exception();
}
};
shared_ptr を使っていない実装だったらこの find は const メンバ関数で良い。しかし、shared_ptr の為に、関数が返るときに、このオブジェクトの内部状態は変更する。そして、C++ のコンパイラはこの変更を正しく、検知できずにエラーとしてコンパイルを異常終了することが出来ない。そして、const 関数のため、変数の変更がオブジェクトに正しく反映されないコードが生成される。これは実装のバグ。
このバグが厄介なのは、オブジェクトが想定外の所で破棄され、その破棄されたオブジェクトに後々アクセスした場合に、セグメンテーション違反を起こす事。core ファイルをデバッガで覗いても本当の問題とは全く別の場所がでてくる。その為、core ファイルは役に経つどころか、迷宮への入口。スタックトレースを見て、この関数が問題を起こしているのにたどり着けるのは、余程の経験と知識があり、かつ感のいい技術者のみ。一般的な技術者では、数回ぐらい懇切丁寧に説明したくらいでは、何が起きているのかも把握できない。
山あり谷ありを越えてたどり着いた結論は、shared_ptr は頼らない方が楽だ。
コメント
トラックバック
このエントリのトラックバックURL: http://uyota.asablo.jp/blog/2012/04/15/6411855/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。