fork(4) download
  1. #include <exception>
  2. #include <utility>
  3. #include <type_traits>
  4.  
  5. template<typename F, typename CleanupPolicy>
  6. class scope_guard : CleanupPolicy, CleanupPolicy::installer
  7. {
  8. using CleanupPolicy::cleanup;
  9. using CleanupPolicy::installer::install;
  10.  
  11. typename std::remove_reference<F>::type f_;
  12.  
  13. public:
  14. scope_guard(F&& f) : f_(std::forward<F>(f)) {
  15. install();
  16. }
  17. ~scope_guard() {
  18. cleanup(f_);
  19. }
  20. };
  21.  
  22. struct unchecked_install_policy {
  23. void install() { }
  24. };
  25.  
  26. struct checked_install_policy {
  27. void install() {
  28. if (std::uncaught_exception()) {
  29. std::terminate(); // sorry
  30. }
  31. }
  32. };
  33.  
  34. struct exit_policy {
  35. typedef unchecked_install_policy installer;
  36.  
  37. template<typename F>
  38. void cleanup(F& f) {
  39. f();
  40. }
  41. };
  42.  
  43. struct failure_policy {
  44. typedef checked_install_policy installer;
  45.  
  46. template<typename F>
  47. void cleanup(F& f) {
  48. // Only cleanup if we're exiting from an exception.
  49. if (std::uncaught_exception()) {
  50. f();
  51. }
  52. }
  53. };
  54.  
  55. struct success_policy {
  56. typedef checked_install_policy installer;
  57.  
  58. template<typename F>
  59. void cleanup(F& f) {
  60. // Only cleanup if we're NOT exiting from an exception.
  61. if (!std::uncaught_exception()) {
  62. f();
  63. }
  64. }
  65. };
  66.  
  67. //////////////////////////////////////////////
  68. // Syntactical sugar
  69. //////////////////////////////////////////////
  70.  
  71. template<typename CleanupPolicy>
  72. struct scope_guard_builder { };
  73.  
  74. template<typename F, typename CleanupPolicy>
  75. scope_guard<F,CleanupPolicy>
  76. operator+(
  77. scope_guard_builder<CleanupPolicy> builder,
  78. F&& f
  79. )
  80. {
  81. return std::forward<F>(f);
  82. }
  83.  
  84. // typical preprocessor utility stuff.
  85. #define PASTE_TOKENS2(a,b) a ## b
  86. #define PASTE_TOKENS(a,b) PASTE_TOKENS2(a,b)
  87.  
  88. #define scope(condition) \
  89.   auto PASTE_TOKENS(_scopeGuard, __LINE__) = \
  90.   scope_guard_builder<condition##_policy>() + [&]
  91.  
  92. //////////////////////////////////////////////
  93. // User code from here on
  94. //////////////////////////////////////////////
  95.  
  96. #include <iostream>
  97.  
  98. struct HasScopeExitInDtor {
  99. ~HasScopeExitInDtor() {
  100. scope (exit) {
  101. std::cout << "scope (exit) in dtor success test\n";
  102. };
  103. try {
  104. std::cout << "scope (exit) in dtor failure test\n";
  105. throw 1;
  106. } catch (...) { }
  107. }
  108. };
  109.  
  110. struct HasScopeSuccessInDtor {
  111. ~HasScopeSuccessInDtor() {
  112. std::cout << std::flush;
  113. scope (success) {
  114. std::cout << "error: scope (success) used in dtor\n";
  115. };
  116. }
  117. };
  118.  
  119. int main()
  120. {
  121. {
  122. const char* captureTest = nullptr;
  123. scope (exit) {
  124. std::cout << "scope (exit) success test\n";
  125. std::cout << "captureTest: " << captureTest;
  126. };
  127. scope (success) {
  128. std::cout << "scope (success) success test\n";
  129. };
  130. scope (failure) {
  131. std::cout << "scope (failure) success test\n";
  132. };
  133. captureTest = "ok\n";
  134. }
  135. try {
  136. HasScopeSuccessInDtor s;
  137.  
  138. scope (exit) {
  139. std::cout << "scope (exit) failure test\n";
  140. };
  141. scope (success) {
  142. std::cout << "scope (success) failure test\n";
  143. };
  144. scope (failure) {
  145. std::cout << "scope (failure) failure test\n";
  146. };
  147.  
  148. HasScopeExitInDtor e;
  149.  
  150. throw 1;
  151. } catch (...) { }
  152. }
Runtime error #stdin #stdout #stderr 0s 3428KB
stdin
Standard input is empty
stdout
scope (success) success test
scope (exit) success test
captureTest: ok
scope (exit) in dtor failure test
scope (exit) in dtor success test
scope (failure) failure test
scope (exit) failure test
stderr
terminate called without an active exception