userver: userver/utils/scope_guard.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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