Created
March 8, 2026 07:30
-
-
Save eao197/6725719d9e7809ae5c7a279a70dab9cc to your computer and use it in GitHub Desktop.
Простой тест производительности разных подходов к очистке ресурсов при исключении
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <array> | |
| #include <chrono> | |
| #include <iostream> | |
| #include <stdexcept> | |
| class duration_meter | |
| { | |
| const char * _name; | |
| const std::chrono::high_resolution_clock::time_point _started_at; | |
| public: | |
| duration_meter( const char * name ) | |
| : _name{ name } | |
| , _started_at{ std::chrono::high_resolution_clock::now() } | |
| {} | |
| ~duration_meter() | |
| { | |
| const auto f = std::chrono::high_resolution_clock::now(); | |
| std::cout << "*** " << _name << ": " | |
| << std::chrono::duration_cast<std::chrono::microseconds>( | |
| f - _started_at ).count() | |
| << "us *** " << std::endl; | |
| } | |
| }; | |
| template<typename Lambda> | |
| decltype(auto) | |
| measure( const char * name, Lambda && lambda ) | |
| { | |
| duration_meter meter{ name }; | |
| return lambda(); | |
| } | |
| class pointers_producer | |
| { | |
| public: | |
| static constexpr std::size_t values_count = 100; | |
| private: | |
| std::array<int, values_count> m_values; | |
| std::size_t m_current{}; | |
| public: | |
| pointers_producer() = default; | |
| [[nodiscard]] | |
| int * | |
| next() | |
| { | |
| if(m_current >= values_count) | |
| throw std::runtime_error{ "index out of range" }; | |
| return std::addressof(m_values[ m_current++ ]); | |
| } | |
| }; | |
| using pointers_array = std::array<int *, pointers_producer::values_count + 1>; | |
| class no_reaction_case | |
| { | |
| pointers_array m_pointers; | |
| public: | |
| no_reaction_case(pointers_producer & producer) | |
| { | |
| std::size_t i = 0; | |
| for(; i != std::size(m_pointers); ++i) | |
| { | |
| m_pointers[ i ] = producer.next(); | |
| *(m_pointers[ i ]) = 0; | |
| } | |
| } | |
| [[nodiscard]] | |
| int | |
| sum() const | |
| { | |
| int r = 0; | |
| for(const int * p : m_pointers) | |
| { | |
| r += *p; | |
| } | |
| return r; | |
| } | |
| }; | |
| class catch_case | |
| { | |
| pointers_array m_pointers; | |
| public: | |
| catch_case(pointers_producer & producer) | |
| { | |
| std::size_t i = 0; | |
| try | |
| { | |
| for(; i != std::size(m_pointers); ++i) | |
| { | |
| m_pointers[ i ] = producer.next(); | |
| *(m_pointers[ i ]) = 0; | |
| } | |
| } | |
| catch(...) | |
| { | |
| for(std::size_t j = 0; j != i; ++j) | |
| *(m_pointers[ j ]) = -1; | |
| throw; | |
| } | |
| } | |
| [[nodiscard]] | |
| int | |
| sum() const | |
| { | |
| int r = 0; | |
| for(const int * p : m_pointers) | |
| { | |
| r += *p; | |
| } | |
| return r; | |
| } | |
| }; | |
| class rollback_case | |
| { | |
| pointers_array m_pointers; | |
| public: | |
| rollback_case(pointers_producer & producer) | |
| { | |
| class init_trx | |
| { | |
| pointers_array & m_array; | |
| std::size_t & m_index; | |
| bool m_committed{ false }; | |
| public: | |
| init_trx(pointers_array & array, std::size_t & index) | |
| : m_array{ array } | |
| , m_index{ index } | |
| {} | |
| ~init_trx() | |
| { | |
| if(!m_committed) | |
| { | |
| for(std::size_t j = 0; j != m_index; ++j) | |
| *(m_array[ j ]) = -1; | |
| } | |
| } | |
| void | |
| commit() { m_committed = true; } | |
| }; | |
| std::size_t i = 0; | |
| init_trx trx{ m_pointers, i }; | |
| for(; i != std::size(m_pointers); ++i) | |
| { | |
| m_pointers[ i ] = producer.next(); | |
| *(m_pointers[ i ]) = 0; | |
| } | |
| trx.commit(); | |
| } | |
| [[nodiscard]] | |
| int | |
| sum() const | |
| { | |
| int r = 0; | |
| for(const int * p : m_pointers) | |
| { | |
| r += *p; | |
| } | |
| return r; | |
| } | |
| }; | |
| template<typename Case> | |
| unsigned int | |
| do_check() | |
| { | |
| unsigned int number_of_exceptions = 0; | |
| for(unsigned int i = 0; i < 5'000'000; ++i) | |
| { | |
| try | |
| { | |
| pointers_producer producer; | |
| Case checking_case{ producer }; | |
| if(0 != checking_case.sum()) | |
| std::cerr << "unexpected result!" << std::endl; | |
| } | |
| catch(...) | |
| { | |
| ++number_of_exceptions; | |
| } | |
| } | |
| return number_of_exceptions; | |
| } | |
| int main() | |
| { | |
| const auto no_reaction_r = measure( "no reaction", | |
| []() { | |
| return do_check<no_reaction_case>(); | |
| }); | |
| const auto catch_reaction_r = measure( "catch reaction", | |
| []() { | |
| return do_check<catch_case>(); | |
| }); | |
| const auto rollback_reaction_r = measure( "rollback reaction", | |
| []() { | |
| return do_check<rollback_case>(); | |
| }); | |
| std::cout << "no reaction: " << no_reaction_r << std::endl; | |
| std::cout << "catch reaction: " << catch_reaction_r << std::endl; | |
| std::cout << "rollback reaction: " << rollback_reaction_r << std::endl; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment