SergiusTheBest/ScopeExit
Introduction
ScopeExit library provides an efficient and convenient way to execute statements when execution flow leaves current scope. It implements a so-called scope guard idiom and defines 3 type of guards:
SCOPE_EXIT
- statements are always executed on scope exitSCOPE_SUCCESS
- statements are executed on scope exit when no exceptions have been thrownSCOPE_FAILURE
- statements are executed when scope is leaving due to an exception
Competing C++ scope exit/guard libraries
Other resources
Sample
Here is a simple sample that prints htlm code. Scope exit blocks make sure that html tags are properly closed:
#include <iostream>
#include <ScopeExit/ScopeExit.h>
using namespace std;
int main()
{
cout << "<html>" << endl;
SCOPE_EXIT{ cout << "</html>" << endl; };
{
cout << "<head>" << endl;
SCOPE_EXIT{ cout << "</head>" << endl; };
cout << "<title>Hello</title>" << endl;
}
cout << "<body>" << endl;
SCOPE_EXIT{ cout << "</body>" << endl; };
cout << "<h1>Hello World!</h1>" << endl;
return 0;
}
NOTE: 输出如下:
<html> <head> <title>Hello</title> </head> <body> </body> <h1>Hello World!</h1> </html>
Read code
ScopeExit/include/ScopeExit/ScopeExit.h
它的实现原理是在object的destructor中调用call back。
#pragma once
//
// Usage:
//
// SCOPE_EXIT{ cout << "hello"; }; // will be called at the scope exit
//
#define SCOPE_EXIT_CAT2(x, y) x##y
#define SCOPE_EXIT_CAT(x, y) SCOPE_EXIT_CAT2(x, y)
#define SCOPE_EXIT const auto SCOPE_EXIT_CAT(scopeExit_, __COUNTER__) = ScopeExit::MakeScopeExit() += [&]
namespace ScopeExit
{
template<typename F>
class ScopeExit
{
public:
explicit ScopeExit(F&& fn) : m_fn(fn)
{
}
~ScopeExit()
{
m_fn();
}
ScopeExit(ScopeExit&& other) : m_fn(std::move(other.m_fn))
{
}
private:
ScopeExit(const ScopeExit&);
ScopeExit& operator=(const ScopeExit&);
private:
F m_fn;
};
struct MakeScopeExit
{
template<typename F>
ScopeExit<F> operator+=(F&& fn)
{
return ScopeExit<F>(std::move(fn));
}
};
}
需要结合usage来理解SCOPE_EXIT
的实现:
SCOPE_EXIT{ cout << "hello"; }
会被替换为:
const auto SCOPE_EXIT_CAT(scopeExit_, __COUNTER__) = ScopeExit::MakeScopeExit() += [&]{ cout << "hello"; }
SCOPE_EXIT_CAT
用于生成object的name。
ScopeExit/include/ScopeExit/ScopeFailure.h
和 ScopeExit
类似,所不同的是在destructor中,会通过调用 std::uncaught_exception()
来判断是否抛出了exception。
#pragma once
#include <exception>
//
// Usage:
//
// SCOPE_FAILURE{ cout << "hello"; }; // will be called at the scope exit in case of failure (exception is thrown)
//
#define SCOPE_FAILURE_CAT2(x, y) x##y
#define SCOPE_FAILURE_CAT(x, y) SCOPE_FAILURE_CAT2(x, y)
#define SCOPE_FAILURE const auto SCOPE_FAILURE_CAT(scopeFailure_, __COUNTER__) = ScopeExit::MakeScopeFailure() += [&]
namespace ScopeExit
{
template<typename F>
class ScopeFailure
{
public:
explicit ScopeFailure(F&& fn) : m_fn(fn)
{
}
~ScopeFailure()
{
if (std::uncaught_exception())
{
m_fn();
}
}
ScopeFailure(ScopeFailure&& other) : m_fn(std::move(other.m_fn))
{
}
private:
ScopeFailure(const ScopeFailure&);
ScopeFailure& operator=(const ScopeFailure&);
private:
F m_fn;
};
struct MakeScopeFailure
{
template<typename F>
ScopeFailure<F> operator+=(F&& fn)
{
return ScopeFailure<F>(std::move(fn));
}
};
}
ScopeExit/include/ScopeExit/ScopeSuccess.h
#pragma once
#include <exception>
//
// Usage:
//
// SCOPE_SUCCESS{ cout << "hello"; }; // will be called at the scope success in case of success (no exception is thrown)
//
#define SCOPE_SUCCESS_CAT2(x, y) x##y
#define SCOPE_SUCCESS_CAT(x, y) SCOPE_SUCCESS_CAT2(x, y)
#define SCOPE_SUCCESS const auto SCOPE_SUCCESS_CAT(scopeSuccess_, __COUNTER__) = ScopeExit::MakeScopeSuccess() += [&]
namespace ScopeExit
{
template<typename F>
class ScopeSuccess
{
public:
explicit ScopeSuccess(F&& fn) : m_fn(fn)
{
}
~ScopeSuccess()
{
if (!std::uncaught_exception())
{
m_fn();
}
}
ScopeSuccess(ScopeSuccess&& other) : m_fn(std::move(other.m_fn))
{
}
private:
ScopeSuccess(const ScopeSuccess&);
ScopeSuccess& operator=(const ScopeSuccess&);
private:
F m_fn;
};
struct MakeScopeSuccess
{
template<typename F>
ScopeSuccess<F> operator+=(F&& fn)
{
return ScopeSuccess<F>(std::move(fn));
}
};
}