//file: scopeguard.h
#ifndef _LOKI_SCOPEGUARD_H
#define _LOKI_SCOPEGUARD_H 1
#include <functional>
namespace loki {
class scope_guard_base {
public:
void dismiss() noexcept {_bDismissed = true;}
protected:
scope_guard_base() {}
scope_guard_base(scope_guard_base&& rhs) : _bDismissed(rhs._bDismissed) {rhs._bDismissed = true;}
bool _bDismissed = false;
};
template <typename F>
class scope_guard_impl : public scope_guard_base {
public:
explicit scope_guard_impl(const F& func) : _func(func) {}
explicit scope_guard_impl(F&& func) : _func(std::move(func)) {}
scope_guard_impl(scope_guard_impl&& other) : scope_guard_base(std::move(other)) , _func(std::move(other._func)) {}
~scope_guard_impl() noexcept {if (!_bDismissed) execute();}
private:
void* operator new(size_t) = delete;
void execute() noexcept { _func(); }
F _func;
};
template <typename F>
scope_guard_impl<typename std::decay<F>::type> makeGuard(F&& func) {return scope_guard_impl<typename std::decay<F>::type>(std::forward<F>(func));}
// 一个由临时变量定义的引用,将导致该临时变量的生命周期延长至和此引用一样长,C++保证临时对象一定会被正确的析构,
// makeGuard产生的临时对象tmpobj,赋给guard, guard生命结束时tmpobj同时析构自己,所以有如下定义
typedef scope_guard_base&& scope_guard;
} //namespace loki
#endif //_LOKI_SCOPEGUARD_H
// test program
struct CMateDatabase {
void addMate(const std::string& str1stSex, const std::string& str2ndSex) {
if (str1stSex == str2ndSex) {
std::cout << "Ha oh!!!!!! :" << std::endl;
throw 55;
}
}
};
class CMate {
public:
CMate(CMateDatabase* db, const std::string strSex) : _fCount(0), _pDB(db), _strSex(strSex) {}
std::string getSex() const {return _strSex;}
void addMate(CMate& newMate) {
loki::scope_guard sg = loki::makeGuard(std::bind(&CMate::rollback, this, __FUNCTION__, __LINE__));
_vcMate.push_back(&newMate);
++_fCount;
_pDB->addMate(getSex(), newMate.getSex());
std::cout << "Here's wishing you both a lifetime of happiness!" << std::endl;
sg.dismiss();
}
size_t countMates() const {return _vcMate.size();}
unsigned int _fCount;
private:
void rollback(const char* function, unsigned int line) {
std::cout << "Ban on same-sex marriage! " << std::endl;
_vcMate.pop_back();
--_fCount;
assert (_vcMate.size() == _fCount);
}
std::vector<CMate*> _vcMate;
CMateDatabase* _pDB;
std::string _strSex;
};
int main(int argc, char *argv[]) {
CMateDatabase db;
CMate mate1(&db, "male");
CMate mate2(&db, "female");
CMate mate3(&db, "male");
try {
mate1.addMate(mate2);
}
catch(...) {}
try {
mate1.addMate(mate3);
}
catch(...) {}
return 0;
}