RAII
詳しい文脈は忘れてしまったけど、読書会で「C++はデストラクタが弱い」的な話題があがった。
その場はRAII*1使えばいいよ、とだけ言って概要のみ説明しただけだったので補足を。
まずは、RAIIの実例を知ってもらう為に、簡単なサンプルの紹介から。
void write_to_file(const std::vector<std::string>& vec) { std::ofstream fout("out.txt"); std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(fout, "\n")); }
このプログラムでは、ファイルストリームのオープンもクローズも明示的に行っていないにもかかわらず、どちらも正しく行われる。
これは、コンストラクタ内部でオープンを行い、デストラクタ内部でクローズを行うことで実現されている。
この「コンストラクタでリソースを取得し、デストラクタで返却する」というイディオムをC++ではRAIIと呼んでいる。
擬似的なコード*2は以下のようになる。
class ofstream { FILE* fp; // コピーはいろいろ面倒になるので禁止しておくのが無難 ofstream(const ofstream&); ofstream& operator=(const ofstream&); // newも禁止しておきたければ void* operator new(std::size_t); void* operator new[](std::size_t); public: ofstream(const char* path) { // コンストラクタ内部でオープンして fp = std::fopen(path, "w"); } ~ofstream() { // デストラクタ内部でクローズする std::fclose(fp); } ... };
GCなんて所詮メモリという一リソースの解放を手伝ってくれるだけに過ぎないけど、C++のデストラクタはメモリ以外のリソースの解放を自動化してくれるということですね。
RAIIを知ってしまうと、むしろC++のデストラクタがすばらしく見えてくるはず!