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 {
29public:
30 using Callback = std::function<void()>;
31
32 explicit ScopeGuard(Callback callback)
33 : callback_(std::move(callback)), exceptions_on_enter_(std::uncaught_exceptions()) {}
34
35 ScopeGuard(const ScopeGuard&) = delete;
36 ScopeGuard(ScopeGuard&&) = delete;
37
38 ScopeGuard& operator=(const ScopeGuard&) = delete;
39 ScopeGuard& operator=(ScopeGuard&&) = delete;
40
41 ~ScopeGuard() noexcept(false) {
42 if (!callback_) return;
43
44 if (std::uncaught_exceptions() != exceptions_on_enter_) {
45 // keep all exceptions inside the destructor to avoid std::terminate
46 try {
47 callback_();
48 } catch (const std::exception& e) {
49 UASSERT_MSG(false, "exception is thrown during stack unwinding");
50 LOG_ERROR() << "Exception is thrown during stack unwinding - ignoring: " << e;
51 }
52 } else {
53 // safe to throw
54 callback_();
55 }
56 }
57
58 void Release() noexcept { callback_ = {}; }
59
60private:
61 Callback callback_;
62 const int exceptions_on_enter_;
63};
64
65} // namespace utils
66
67USERVER_NAMESPACE_END