Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save eao197/6725719d9e7809ae5c7a279a70dab9cc to your computer and use it in GitHub Desktop.

Select an option

Save eao197/6725719d9e7809ae5c7a279a70dab9cc to your computer and use it in GitHub Desktop.
Простой тест производительности разных подходов к очистке ресурсов при исключении
#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