きままにブログ

プログラミングを主とした私のメモ帳です。寂しいのでコメントください笑

例外安全

RAII

RAIIは、リソースはコンストラクタだけで確保され、デストラクタで解放されるクラス構成等を指す。つまり、コンストラクタ以外ではnewなど使わなければ良い。

メンバを生ポインタとして持つと、複数の例外等によってコンストラクタから抜け出すときに解放する処理が複雑となってしまうため、スマートポインタを使った方がいい。

基本的には必要がなければポインタは使わないで、普通にメンバを実態として持つ。どうしても必要ならunique_ptrを使い、更にどうしても必要ならshared_ptr、そして参照で持つ。ほんとうにどうしてもアドレス(の操作も含めて)が必要なら、生ポインタを使うが、カプセル化して外部には一切情報を漏らさないといったスタンスがよさそう。

#include <iostream>
#include <exception>
#include <memory>

using namespace std;

struct R {
	R() { cout << "R::R()" << endl; }
	~R() { cout << "R::~R()" << endl; }
};

struct C {
	class CException : exception { };

	unique_ptr<R> p; // ヒープに確保したいメンバ
	unique_ptr<R> p2;
	R r; // 普通のメンバ

	C(int no) try {
		cout << "C::C()" << endl;
		p = make_unique<R>(); // リソース確保
		if(no == 0) {
			throw CException();
		}
		p2 = make_unique<R>(); // リソース確保
		if(no == 1) {
			throw CException();
		}
	}
	catch(const CException&) {
		cout << "rescue!" << endl;
	}
	~C() {
		cout << "C::~C()" << endl;
	}
};

int main() {
	try {
		C c(0);
	}
	catch(const C::CException& e) {
		cout << "Except!" << endl;
	}

	try {
		C c(1);
	}
	catch(const C::CException& e) {
		cout << "Except!" << endl;
	}

	cin.get();
	return 0;
}