std::auto_ptr
http://www.geocities.jp/ky_webid/cpp/library/026.html
これは以前、テンポラリバッファとしてのvector - (void*)Pないとの中で名前だけ出てきましたね。
テンポラリバッファとしての単一オブジェクトをnewするときに便利といった感じなのでしょうか。
見てみましょう。auto_ptrを使うにはmemoryヘッダが必要となります。
#include <iostream> #include <memory> using std::cout; using std::endl; class CSample { public: CSample(int num) { m_num = num; cout << "コンストラクタ" << endl; } ~CSample() { cout << "デストラクタ" << endl; } int getNum () { return m_num; } private: int m_num; }; std::auto_ptr<CSample> create (int num) { std::auto_ptr<CSample> p( new CSample(num) ); return p; } int main () { std::auto_ptr<CSample> p = create(100); cout << p->getNum() << endl; return 0; }
$ main コンストラクタ 100 デストラクタ
createの中でCSampleをnewしているのに、main関数に戻ってきてからデストラクタが呼ばれています。
これはつまり、auto_ptrで定義した変数pがcreate関数を抜けてもその時点ではCSampleをdeleteしていない証拠ですね。
一体この動作はどうやって実現しているのでしょうか?
自身は new で確保された訳ではなく、単なるローカル変数です。なので、暗黙のうちにコピーを取り、戻り値で返した後、デストラクタが呼び出されて破棄されます。この中でコピーという動作がポイントです。auto_ptr型の変数を、コピーすると(代入すると)、その auto_ptr が管理しているポインタが、コピー先に移動し、コピー元の方は NULL になります。
なるほど。
コピーコンストラクタや代入演算した呼ばれたときにauto_ptrが管理しているCSampleのポインタを移動させているわけなんですね。
だからcreate関数でのp変数のデストラクタが呼ばれても、その時点ではポインタが移動しているのでCSampleがdeleteされないんですね。
素晴らしいです。
ですが逆に言えば代入した後の、代入元の変数は使用できないということになりますね。
int main () { std::auto_ptr<CSample> p1( new CSample(100) ); cout << p1->getNum() << endl; // p1をp2に代入すると、p1のCSampleがp2へ移動する std::auto_ptr<CSample> p2 = p1; // よってp1はもう使えない。 cout << p1->getNum() << endl; return 0; }
これを実行するとプログラムが落ちます。
これはこれで微妙ですね。代入しても有効で且つ、一番最後の時にだけCSampleのdeleteが呼ばれれば完璧なんですが。