и Александресков scope_guard и подумал, что неплохо бы иметь в нем 2 метода:
— dismiss(), который отменяет вызов функтора (впрочем, это есть в вышеназванных реализациях)
— commit(), который вызывает функтор еще до того как дело дойдет до деструктора.
Придумалось вот такое решение:
class scope_guard_base {
scope_guard_base& operator=(const scope_guard_base&);
protected:
typedef void (*commit_fn)(const scope_guard_base*);
mutable commit_fn m_commit; //функция коммита - устанавливается потомком
scope_guard_base(commit_fn f)
:m_commit(f)
{}
scope_guard_base(const scope_guard_base& rhs)
:m_commit(rhs.m_commit)
{ rhs.m_commit = 0; }
public:
~scope_guard_base()
{
try{
if( m_commit )
m_commit( this );
}catch(...){
// некузяво бросаться исключениями из деструктора...
}
}
void dismiss() const
{ m_commit = 0; }
void commit() const
{
if( !m_commit ) return;
commit_fn fn = m_commit;
m_commit = 0;//коммитимся прямо сейчас - деструктору делать нечего.
fn( this );
}
};
template<class F> class scope_guard_impl
:public scope_guard_base
{
static void do_commit(const scope_guard_base* g);
F m_f;
public:
scope_guard_impl(const F& f)
:scope_guard_base(do_commit)
,m_f(f)
{}
};
template<class F>
void scope_guard_impl<F>::do_commit(const scope_guard_base* g)
{
((scope_guard*)g)->m_f();
}
//все остальное как у MaximE и Александреску
Итак, плюсы:
— появился метод commit()
А теперь минусы:
— функция scope_guard_impl::do_commit() никак не может стать inline (компилятор не даст) потому что на нее имеется указатель. В принципе, это не так уж и страшно (особенно, если ее сделать __fastcall) — кода она негенерит считанные байты — но неприятный осадок все равно остается
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
и Александресков scope_guard и подумал, что неплохо бы иметь в нем 2 метода:
TMH>- dismiss(), который отменяет вызов функтора (впрочем, это есть в вышеназванных реализациях) TMH>- commit(), который вызывает функтор еще до того как дело дойдет до деструктора.
Честно говоря, я подумывал об этом но не смог придумать применение для этого нового метода.
[]
TMH>А теперь минусы: TMH>- функция scope_guard_impl::do_commit() никак не может стать inline (компилятор не даст) потому что на нее имеется указатель. В принципе, это не так уж и страшно (особенно, если ее сделать __fastcall) — кода она негенерит считанные байты — но неприятный осадок все равно остается
Здравствуйте, MaximE, Вы писали:
ME>Честно говоря, я подумывал об этом но не смог придумать применение для этого нового метода.
Например, если использовать scope_guard для работы с синхронизационными обьектами:
{
some_mutex.lock();
scope_guard g = make_guard(boost::bind(&mutex::unlock, some_mutex));
switch( some_var ) {
case TILITILI:
do_someting(guarded_data);
break;
case TRALIVALI:
do_someting_different(guarded_data);
break;
case YOKSEL:
do_someting_very_different(guarded_data);
break;
case MOKSEL:
do_someting(guarded_data);
//а здесь (и только здесь) идет доолгая операция которая уже не требует блокировок
//держать мютекс смысла уже не имеет - вот commit() здесь и пригодится...
g.commit();
do_some_very_long_operation();
break;
}
}
Конечно, можно сказать, что commit() можно заменить на "g.dismiss(); some_mutex.unlock();",
но это вопрос весьма и весьма философский
ME>- Объект стал "потяжелее".
Неее. Компаунды выравниваются на 4 байта (если больше не надо) — так по крайней мере в MSVC и GCC.
Тем более, что создается-то класс scope_guard_impl, в котором имеется мембер m_f, который (в особенности если пробайндженый) занимает порядком (ну уж не менее 4х байт) и, тоже выравнивается.
Так что утяжеления не будет. Разве что если указатели будут однобайтовые
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Здравствуйте, TepMuHyc, Вы писали:
TMH>Здравствуйте, MaximE, Вы писали:
ME>>Честно говоря, я подумывал об этом но не смог придумать применение для этого нового метода. TMH>Например, если использовать scope_guard для работы с синхронизационными обьектами:
Пример не показателен. Порядок строчек может быть изменен так, что commit не будет нужен.
ME>>- Объект стал "потяжелее". TMH>Неее. Компаунды выравниваются на 4 байта (если больше не надо) — так по крайней мере в MSVC и GCC. TMH>Тем более, что создается-то класс scope_guard_impl, в котором имеется мембер m_f, который (в особенности если пробайндженый) занимает порядком (ну уж не менее 4х байт) и, тоже выравнивается. TMH>Так что утяжеления не будет. Разве что если указатели будут однобайтовые
Прости, просмотрел, что указателем на функцию заменили bool.
Здравствуйте, MaximE, Вы писали:
ME>Пример не показателен. Порядок строчек может быть изменен так, что commit не будет нужен.
Естественно, не показателен (я ж говорил, что вопрос философский).
Да и любой другой пример показательным не будет. Просто мне кажется что иметь такой метод будет удобно. Вот и все.
Вопрос стОит ли этот метод тех жертв на которые пошла данная реализация класса, оставляю открытым — я сам еще не определился
Кстати, все это мне напоминает одну давнюю дискуссию зачем нужны битовые операции or и xor если их легко выразить через and .
Кстати, скомпилил я свой гард со включенной на полную катушку оптимизацией, и оказалось что do_commit() генерит всего семь байтов кода когда она fastcall и 16 байтов когда без модификатора.
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Здравствуйте, TepMuHyc, Вы писали:
TMH>Да и любой другой пример показательным не будет. Просто мне кажется что иметь такой метод будет удобно. Вот и все.
Вот тут собака и зарыта. Стоит ли включать функциональность, которая не необходима, но *может когда-нибудь понадобиться*, а потом еще и поддерживать ее, чтобы не разбить *возможных существующих клиентов* этой функциональности?
Здравствуйте, MaximE, Вы писали:
ME>Для себя я однозначно решил этот вопрос —
Я, как человек ленивый, и к тому же пишущий дофига кода который используется кем-то еще, этот вопрос решил несколько по другому . Знаешь, очень неприятно лезть в файл и с риском приволочь кучу багов править его только потому что кому-то жизнь не мила из-за того что полгода назад было лень дописать функцию do_something().
...И что еще хуже, этот кто-то полезет своими потными ручками дописывать эту функцию
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.