Transactional Programming
More C++ Idioms/Scope Guard
예외가 발생했을 때 자동 원상 복구가 가능할까… 아래는 ScopeGuard idiom.
#include
#include
using namespace std;
class ScopeGuard {
char *mem;
bool dismissed;
public:
ScopeGuard(char *m):mem(m), dismissed(false) {
}
~ScopeGuard() {
if (!dismissed) {
cout << "Deallocating by ScopeGuard." << endl;
delete[] mem;
}
else {
cout << "Already deallocated." << endl;
}
}
void Dismiss() {
dismissed = true;
}
};
void foo() {
char *a = new char[10];
ScopeGuard sg(a);
throw "error";
}
void bar() {
char *a = new char[10];
ScopeGuard sg(a);
delete[] a;
cout << "Dismissing" << endl;
sg.Dismiss();
}
int main()
{
try {
foo();
}
catch (char const *s) {
}
bar();
return EXIT_SUCCESS;
}
[/code]
결론을 말씀드리면 안됩니다.
이유는 ScopeGuard를 std::vector 등에 적용되었을 때 보면, insert한걸 다시 delete하거나 delete한걸 다시 insert하도록 ScopeGuard의 소멸자를 작성하여야 하기 때문. delete한걸 자동 insert하는 소멸자를 만든다고 할 때, 아쉽게도 vector의 insert는 fail이 가능함. 만약 ScopeGuard가 소멸자에서 자동 insert중 fail한다면 갈데가 없음.
해결책은 DBMS의 rollback처럼 implicit 하게 동작을 로깅하도록 하는 것. 그리고 delete시에 실제로 element를 삭제해버리지 말고 메모리상에 저장해두었다가 rollback시엔 메모리 링크만 새로 이어줌.