More C++ Idioms/リソースの返値(Resource Return)
リソースの返値(Resource Return)
[編集]意図
[編集](リソースの)所有権移動を、ファクトリ関数の返値の型によって明示的に表明する。
別名
[編集]動機
[編集]新しいリソースを作成し呼び出し元に返すために、しばしばファクトリ関数が使われる。 新しいリソースは、生のメモリや、動的に割り当てられたオブジェクト、データベースのカーソルや接続、ロックといったものになりうる。 誰がリソースを所有し、誰がリソースを解放するかは、リソースに関する重要な質問である。 呼び出し元がリソースの解放に対して暗黙的に責任を持つようなインタフェースが作成されることがよくある。 この点に呼び出し元が気づいていない場合、あるいは、正しい手順をとるのを忘れていた場合、簡単に誤用される類のインタフェースになってしまう。 以下のコード断片のような例である。
struct X
{
void foo() {}
};
X * Xfactory() // リソースの所有権が暗黙的に呼び出し元に移動する。
{
return new X; // 動的に割り当てられたインスタンス
}
int main (void)
{
Xfactory()->foo(); // ここで動的に割り当てられた X のインスタンスがリーク(解放漏れ)する。
}
リソースの返値(Resource Return)イディオムは状況を是正し、結果、 (いくらかは)簡単には誤用できないインタフェースをもたらす。
解法とサンプルコード
[編集]その解法は、リソース管理を行うスマートポインタにリソースをラップし、生のポインタの代わりスマートポインタを返すことである。 もっとも単純な形式のリソースの返値(Resource Return)イディオムは以下のコード断片のようになる。
struct X
{
void foo() {}
};
std::auto_ptr<X> Xfactory() // リソースの所有権は明示的に呼び出し元に移動される。
{
return std::auto_ptr<X> (new X); // 動的に割り当てられたインスタンス
}
int main (void)
{
Xfactory()->foo(); // ここでは、動的に割り当てられた X のインスタンスはリークしない。
}
リソースを返すためのリソース管理用スマートポインタの型を決定する際に、考慮するべき点がいくつかある。 選択肢としては、
- std::auto_ptr
- boost::shared_ptr
- ユーザー定義のハンドル・ボディ(Handle Body)イディオム
がある。
選択に対する利点と欠点についての素晴らしい議論が、Scott Meyers の記事 The Resource Return Problem で詳細に記述されている。 (単純な delete 以外の)カスタム化された削除が必要とならない限り、 前記の例のように、 auto_ptr がリソースの返値(Resource Return)イディオムを使う素早い方法である。 auto_ptr は排他的だが移動可能なリソースの所有権を提供し、それはインタフェースを見ただけで非常に明快となる。 動的に割り当てられたポインタを返すファクトリ関数にとって、boost::shared_ptr もよい選択肢である。なぜなら、通常の copy semantics (例えば、STL のコンテナに格納することができる)を提供するからである。 また、クライアントを邪魔することなく、リソースの解放方法を通常の delete 操作から、カスタム化された方法に変更することもできる。
リソースの返値(Resource Return)イディオムに排他的な所有権が含まれている場合、 所有権移動コンストラクタ(Move Constructor)イディオムが、 リソース所有権の移動中におけるテンポラリオブジェクトの不要な生成と破壊を避けるために しばしば有用である。