ScopeExit.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /* RAII class for executing arbitrary actions at scope end. */
  7. #ifndef mozilla_ScopeExit_h
  8. #define mozilla_ScopeExit_h
  9. /*
  10. * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf for a
  11. * standards-track version of this.
  12. *
  13. * Error handling can be complex when various actions need to be performed that
  14. * need to be undone if an error occurs midway. This can be handled with a
  15. * collection of boolean state variables and gotos, which can get clunky and
  16. * error-prone:
  17. *
  18. * {
  19. * if (!a.setup())
  20. * goto fail;
  21. * isASetup = true;
  22. *
  23. * if (!b.setup())
  24. * goto fail;
  25. * isBSetup = true;
  26. *
  27. * ...
  28. * return true;
  29. *
  30. * fail:
  31. * if (isASetup)
  32. * a.teardown();
  33. * if (isBSetup)
  34. * b.teardown();
  35. * return false;
  36. * }
  37. *
  38. * ScopeExit is a mechanism to simplify this pattern by keeping an RAII guard
  39. * class that will perform the teardown on destruction, unless released. So the
  40. * above would become:
  41. *
  42. * {
  43. * if (!a.setup()) {
  44. * return false;
  45. * }
  46. * auto guardA = MakeScopeExit([&] {
  47. * a.teardown();
  48. * });
  49. *
  50. * if (!b.setup()) {
  51. * return false;
  52. * }
  53. * auto guardB = MakeScopeExit([&] {
  54. * b.teardown();
  55. * });
  56. *
  57. * ...
  58. * guardA.release();
  59. * guardB.release();
  60. * return true;
  61. * }
  62. *
  63. * This header provides:
  64. *
  65. * - |ScopeExit| - a container for a cleanup call, automically called at the
  66. * end of the scope;
  67. * - |MakeScopeExit| - a convenience function for constructing a |ScopeExit|
  68. * with a given cleanup routine, commonly used with a lambda function.
  69. *
  70. * Note that the RAII classes defined in this header do _not_ perform any form
  71. * of reference-counting or garbage-collection. These classes have exactly two
  72. * behaviors:
  73. *
  74. * - if |release()| has not been called, the cleanup is always performed at
  75. * the end of the scope;
  76. * - if |release()| has been called, nothing will happen at the end of the
  77. * scope.
  78. */
  79. #include "mozilla/GuardObjects.h"
  80. #include "mozilla/Move.h"
  81. namespace mozilla {
  82. template <typename ExitFunction>
  83. class MOZ_STACK_CLASS ScopeExit {
  84. ExitFunction mExitFunction;
  85. bool mExecuteOnDestruction;
  86. MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
  87. public:
  88. explicit ScopeExit(ExitFunction&& cleanup
  89. MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
  90. : mExitFunction(cleanup)
  91. , mExecuteOnDestruction(true)
  92. {
  93. MOZ_GUARD_OBJECT_NOTIFIER_INIT;
  94. }
  95. ScopeExit(ScopeExit&& rhs)
  96. : mExitFunction(mozilla::Move(rhs.mExitFunction))
  97. , mExecuteOnDestruction(rhs.mExecuteOnDestruction)
  98. {
  99. rhs.release();
  100. }
  101. ~ScopeExit() {
  102. if (mExecuteOnDestruction) {
  103. mExitFunction();
  104. }
  105. }
  106. void release() {
  107. mExecuteOnDestruction = false;
  108. }
  109. private:
  110. explicit ScopeExit(const ScopeExit&) = delete;
  111. ScopeExit& operator=(const ScopeExit&) = delete;
  112. ScopeExit& operator=(ScopeExit&&) = delete;
  113. };
  114. template <typename ExitFunction>
  115. ScopeExit<ExitFunction>
  116. MakeScopeExit(ExitFunction&& exitFunction)
  117. {
  118. return ScopeExit<ExitFunction>(mozilla::Move(exitFunction));
  119. }
  120. } /* namespace mozilla */
  121. #endif /* mozilla_ScopeExit_h */