exception_checker.hpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * https://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * Copyright (c) 2023 Andrey Semashev
  7. */
  8. /*!
  9. * \file scope/exception_checker.hpp
  10. *
  11. * This header contains definition of \c exception_checker type.
  12. */
  13. #ifndef BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
  14. #define BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
  15. #include <boost/assert.hpp>
  16. #include <boost/scope/detail/config.hpp>
  17. #include <boost/core/uncaught_exceptions.hpp>
  18. #include <boost/scope/detail/header.hpp>
  19. #ifdef BOOST_HAS_PRAGMA_ONCE
  20. #pragma once
  21. #endif
  22. namespace boost {
  23. namespace scope {
  24. /*!
  25. * \brief A predicate for checking whether an exception is being thrown.
  26. *
  27. * On construction, the predicate captures the current number of uncaught exceptions,
  28. * which it then compares with the number of uncaught exceptions at the point when it
  29. * is called. If the number increased then a new exception is detected and the predicate
  30. * returns \c true.
  31. *
  32. * \note This predicate is designed for a specific use case with scope guards created on
  33. * the stack. It is incompatible with C++20 coroutines and similar facilities (e.g.
  34. * fibers and userspace context switching), where the thread of execution may be
  35. * suspended after the predicate captures the number of uncaught exceptions and
  36. * then resumed in a different context, where the number of uncaught exceptions
  37. * has changed. Similarly, it is incompatible with usage patterns where the predicate
  38. * is cached after construction and is invoked after the thread has left the scope
  39. * where the predicate was constructed (e.g. when the predicate is stored as a class
  40. * data member or a namespace-scope variable).
  41. */
  42. class exception_checker
  43. {
  44. public:
  45. //! Predicate result type
  46. using result_type = bool;
  47. private:
  48. unsigned int m_uncaught_count;
  49. public:
  50. /*!
  51. * \brief Constructs the predicate.
  52. *
  53. * Upon construction, the predicate saves the current number of uncaught exceptions.
  54. * This information will be used when calling the predicate to detect if a new
  55. * exception is being thrown.
  56. *
  57. * **Throws:** Nothing.
  58. */
  59. exception_checker() noexcept :
  60. m_uncaught_count(boost::core::uncaught_exceptions())
  61. {
  62. }
  63. /*!
  64. * \brief Checks if an exception is being thrown.
  65. *
  66. * **Throws:** Nothing.
  67. *
  68. * \returns \c true if the number of uncaught exceptions at the point of call is
  69. * greater than that at the point of construction of the predicate,
  70. * otherwise \c false.
  71. */
  72. result_type operator()() const noexcept
  73. {
  74. const unsigned int uncaught_count = boost::core::uncaught_exceptions();
  75. // If this assertion fails, the predicate is likely being used in an unsupported
  76. // way, where it is called in a different scope or thread context from where
  77. // it was constructed.
  78. BOOST_ASSERT((uncaught_count - m_uncaught_count) <= 1u);
  79. return uncaught_count > m_uncaught_count;
  80. }
  81. };
  82. /*!
  83. * \brief Creates a predicate for checking whether an exception is being thrown
  84. *
  85. * **Throws:** Nothing.
  86. */
  87. inline exception_checker check_exception() noexcept
  88. {
  89. return exception_checker();
  90. }
  91. } // namespace scope
  92. } // namespace boost
  93. #include <boost/scope/detail/footer.hpp>
  94. #endif // BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_