Bonita Montero
2024-07-02 09:44:29 UTC
For some time I use sth. like experimental::scope_exit, but sth.
more advanced. My class is called invoke_on_destruct and multiple
of these scope-guards can be concatenated. So if you have multiple
data struc- tures which are changed you can revert all changes with
multiple individual scope-guards.
After you changed everything you do sth. like a commit by disabling
the last scope-guard. The enabled state is propagated on destruction
to the depending scope-guards so you only have to disable the last
and all depening scope-guards are disabled also.
#pragma once
#include <utility>
template<typename Fn>
struct invoke_on_destruct;
struct iod_base
{
private:
template<typename Fn>
friend struct invoke_on_destruct;
bool m_enabled;
iod_base *m_next;
iod_base( iod_base *next ) :
m_enabled( true ),
m_next( next )
{
}
void disable()
{
m_enabled = false;
}
};
template<typename Fn>
struct invoke_on_destruct final : public iod_base
{
private:
Fn m_fn;
public:
invoke_on_destruct( Fn &&fn, iod_base *next = nullptr )
requires requires( Fn fn ) { { fn() }; } :
iod_base( next ),
m_fn( std::forward<Fn>( fn ) )
{
}
~invoke_on_destruct()
{
bool enabled = m_enabled;
if( m_next )
m_next->m_enabled = enabled;
if( enabled )
m_fn();
}
void operator ()()
{
m_enabled = false;
m_fn();
}
using iod_base::disable;
};
more advanced. My class is called invoke_on_destruct and multiple
of these scope-guards can be concatenated. So if you have multiple
data struc- tures which are changed you can revert all changes with
multiple individual scope-guards.
After you changed everything you do sth. like a commit by disabling
the last scope-guard. The enabled state is propagated on destruction
to the depending scope-guards so you only have to disable the last
and all depening scope-guards are disabled also.
#pragma once
#include <utility>
template<typename Fn>
struct invoke_on_destruct;
struct iod_base
{
private:
template<typename Fn>
friend struct invoke_on_destruct;
bool m_enabled;
iod_base *m_next;
iod_base( iod_base *next ) :
m_enabled( true ),
m_next( next )
{
}
void disable()
{
m_enabled = false;
}
};
template<typename Fn>
struct invoke_on_destruct final : public iod_base
{
private:
Fn m_fn;
public:
invoke_on_destruct( Fn &&fn, iod_base *next = nullptr )
requires requires( Fn fn ) { { fn() }; } :
iod_base( next ),
m_fn( std::forward<Fn>( fn ) )
{
}
~invoke_on_destruct()
{
bool enabled = m_enabled;
if( m_next )
m_next->m_enabled = enabled;
if( enabled )
m_fn();
}
void operator ()()
{
m_enabled = false;
m_fn();
}
using iod_base::disable;
};