/* * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * https://www.boost.org/LICENSE_1_0.txt) * * Copyright (c) 2023 Andrey Semashev */ /*! * \file scope/exception_checker.hpp * * This header contains definition of \c exception_checker type. */ #ifndef BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_ #define BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_ #include #include #include #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif namespace boost { namespace scope { /*! * \brief A predicate for checking whether an exception is being thrown. * * On construction, the predicate captures the current number of uncaught exceptions, * which it then compares with the number of uncaught exceptions at the point when it * is called. If the number increased then a new exception is detected and the predicate * returns \c true. * * \note This predicate is designed for a specific use case with scope guards created on * the stack. It is incompatible with C++20 coroutines and similar facilities (e.g. * fibers and userspace context switching), where the thread of execution may be * suspended after the predicate captures the number of uncaught exceptions and * then resumed in a different context, where the number of uncaught exceptions * has changed. Similarly, it is incompatible with usage patterns where the predicate * is cached after construction and is invoked after the thread has left the scope * where the predicate was constructed (e.g. when the predicate is stored as a class * data member or a namespace-scope variable). */ class exception_checker { public: //! Predicate result type using result_type = bool; private: unsigned int m_uncaught_count; public: /*! * \brief Constructs the predicate. * * Upon construction, the predicate saves the current number of uncaught exceptions. * This information will be used when calling the predicate to detect if a new * exception is being thrown. * * **Throws:** Nothing. */ exception_checker() noexcept : m_uncaught_count(boost::core::uncaught_exceptions()) { } /*! * \brief Checks if an exception is being thrown. * * **Throws:** Nothing. * * \returns \c true if the number of uncaught exceptions at the point of call is * greater than that at the point of construction of the predicate, * otherwise \c false. */ result_type operator()() const noexcept { const unsigned int uncaught_count = boost::core::uncaught_exceptions(); // If this assertion fails, the predicate is likely being used in an unsupported // way, where it is called in a different scope or thread context from where // it was constructed. BOOST_ASSERT((uncaught_count - m_uncaught_count) <= 1u); return uncaught_count > m_uncaught_count; } }; /*! * \brief Creates a predicate for checking whether an exception is being thrown * * **Throws:** Nothing. */ inline exception_checker check_exception() noexcept { return exception_checker(); } } // namespace scope } // namespace boost #include #endif // BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_