userver: userver/utils/scope_guard.hpp Source File
Loading...
Searching...
No Matches
scope_guard.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/scope_guard.hpp
4/// @brief @copybrief utils::ScopeGuard
5
6#include <exception>
7#include <functional>
8
9#include <userver/logging/log.hpp>
10#include <userver/utils/assert.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace utils {
15
16/// @ingroup userver_universal userver_containers
17///
18/// @brief a helper class to perform actions on scope exit
19///
20/// Usage example:
21/// @snippet universal/src/utils/scope_guard_test.cpp ScopeGuard usage example
22///
23/// @note exception handling is done in such way that std::terminate will not be
24/// called: in the normal path of execution, exception from handler will
25/// propagate into client code, but if we leave scope because of an exception,
26/// handler's exception, if thrown, will be silenced and written into log to
27/// avoid std::terminate
28class ScopeGuard final {
29 public:
30 using Callback = std::function<void()>;
31
32 explicit ScopeGuard(Callback callback)
33 : callback_(std::move(callback)),
34 exceptions_on_enter_(std::uncaught_exceptions()) {}
35
36 ScopeGuard(const ScopeGuard&) = delete;
37 ScopeGuard(ScopeGuard&&) = delete;
38
39 ScopeGuard& operator=(const ScopeGuard&) = delete;
40 ScopeGuard& operator=(ScopeGuard&&) = delete;
41
42 ~ScopeGuard() noexcept(false) {
43 if (!callback_) return;
44
45 if (std::uncaught_exceptions() != exceptions_on_enter_) {
46 // keep all exceptions inside the destructor to avoid std::terminate
47 try {
48 callback_();
49 } catch (const std::exception& e) {
50 UASSERT_MSG(false, "exception is thrown during stack unwinding");
51 LOG_ERROR() << "Exception is thrown during stack unwinding - ignoring: "
52 << e;
53 }
54 } else {
55 // safe to throw
56 callback_();
57 }
58 }
59
60 void Release() noexcept { callback_ = {}; }
61
62 private:
63 Callback callback_;
64 const int exceptions_on_enter_;
65};
66
67} // namespace utils
68
69USERVER_NAMESPACE_END