-
Notifications
You must be signed in to change notification settings - Fork 10
/
scope.hpp
82 lines (69 loc) · 2.38 KB
/
scope.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (c) 2017-2018 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt
#pragma once
#ifndef NYTL_INCLUDE_SCOPE
#define NYTL_INCLUDE_SCOPE
#include <nytl/nonCopyable.hpp> // nytl::NonMovable
#include <exception> // std::uncaught_exceptions
#include <iostream> // std::cerr
namespace nytl {
/// \brief Can be used to execute code when going out of the current scope.
/// This enables to handle non-RAII resources in a pseudo-RAII manner without
/// having to define own wrapper functions.
/// Example for how this could be useful for e.g. file descriptors.
/// Note that no matter which way we take out of the shown scope
/// (exception, early return or just coming to the scopes end) the given scope
/// guard will be executed and the fd closed.
/// All exceptions will always be caught and outputted to cerr.
/// ```cpp
/// {
/// auto fd = ::open("test.txt");
/// auto fdGuard = nytl::ScopeGuard([=]{ ::close(fd); }};
///
/// if(condition()) return;
/// functionThatMightThrow();
/// }
/// ```
template<typename F, bool OnSuccess = true, bool OnException = true>
class ScopeGuard : public nytl::NonMovable {
public:
static_assert(OnSuccess || OnException);
public:
ScopeGuard(F&& func) :
func_(std::forward<F>(func)),
exceptions_(std::uncaught_exceptions()) {}
~ScopeGuard() noexcept {
try {
auto ne = exceptions_ < std::uncaught_exceptions();
if((OnSuccess && !ne) || (OnException && ne)) {
func_();
}
} catch(const std::exception& err) {
std::cerr << "~nytl::ScopeGuard: exception while unwinding: ";
std::cerr << err.what() << std::endl;
} catch(...) {
std::cerr << "~nytl::ScopeGuard: caught non-exception while ";
std::cerr << "unwinding" << std::endl;
}
}
protected:
F func_;
int exceptions_;
};
/// Utility shortcuts to only execute a function when the scope is left
/// with/without exceptions. See ScopeGuard for details.
template<typename F>
class SuccessGuard : public ScopeGuard<F, true, false> {
public:
using ScopeGuard<F, true, false>::ScopeGuard;
};
template<typename F>
class ExceptionGuard : public ScopeGuard<F, false, true> {
public:
using ScopeGuard<F, false, true>::ScopeGuard;
};
template<typename F> SuccessGuard(F&&) -> SuccessGuard<F>;
template<typename F> ExceptionGuard(F&&) -> ExceptionGuard<F>;
} // namespace nytl
#endif // header guard