Еще один scope_guard - с наворотами
От: TepMuHyc  
Дата: 23.09.03 10:28
Оценка: 9 (1)
Посмотрел я на МаксимовЕ
Автор: MaximE
Дата: 21.09.03
и Александресков 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.
Re: Еще один scope_guard - с наворотами
От: MaximE Великобритания  
Дата: 23.09.03 10:34
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Посмотрел я на МаксимовЕ
Автор: MaximE
Дата: 21.09.03
и Александресков scope_guard и подумал, что неплохо бы иметь в нем 2 метода:


TMH>- dismiss(), который отменяет вызов функтора (впрочем, это есть в вышеназванных реализациях)

TMH>- commit(), который вызывает функтор еще до того как дело дойдет до деструктора.

Честно говоря, я подумывал об этом но не смог придумать применение для этого нового метода.

[]

TMH>А теперь минусы:

TMH>- функция scope_guard_impl::do_commit() никак не может стать inline (компилятор не даст) потому что на нее имеется указатель. В принципе, это не так уж и страшно (особенно, если ее сделать __fastcall) — кода она негенерит считанные байты — но неприятный осадок все равно остается

— Объект стал "потяжелее".
Re[2]: Еще один scope_guard - с наворотами
От: TepMuHyc  
Дата: 23.09.03 11:01
Оценка:
Здравствуйте, 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.
Re[3]: Еще один scope_guard - с наворотами
От: MaximE Великобритания  
Дата: 23.09.03 11:17
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Здравствуйте, MaximE, Вы писали:


ME>>Честно говоря, я подумывал об этом но не смог придумать применение для этого нового метода.

TMH>Например, если использовать scope_guard для работы с синхронизационными обьектами:

Пример не показателен. Порядок строчек может быть изменен так, что commit не будет нужен.

ME>>- Объект стал "потяжелее".

TMH>Неее. Компаунды выравниваются на 4 байта (если больше не надо) — так по крайней мере в MSVC и GCC.
TMH>Тем более, что создается-то класс scope_guard_impl, в котором имеется мембер m_f, который (в особенности если пробайндженый) занимает порядком (ну уж не менее 4х байт) и, тоже выравнивается.
TMH>Так что утяжеления не будет. Разве что если указатели будут однобайтовые

Прости, просмотрел, что указателем на функцию заменили bool.
Re[4]: Еще один scope_guard - с наворотами
От: TepMuHyc  
Дата: 23.09.03 11:35
Оценка:
Здравствуйте, 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.
Re[5]: Еще один scope_guard - с наворотами
От: MaximE Великобритания  
Дата: 23.09.03 11:42
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Да и любой другой пример показательным не будет. Просто мне кажется что иметь такой метод будет удобно. Вот и все.


Вот тут собака и зарыта. Стоит ли включать функциональность, которая не необходима, но *может когда-нибудь понадобиться*, а потом еще и поддерживать ее, чтобы не разбить *возможных существующих клиентов* этой функциональности?

Для себя я однозначно решил этот вопрос —
Re[6]: Еще один scope_guard - с наворотами
От: TepMuHyc  
Дата: 23.09.03 12:30
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Для себя я однозначно решил этот вопрос —

Я, как человек ленивый, и к тому же пишущий дофига кода который используется кем-то еще, этот вопрос решил несколько по другому . Знаешь, очень неприятно лезть в файл и с риском приволочь кучу багов править его только потому что кому-то жизнь не мила из-за того что полгода назад было лень дописать функцию do_something().

...И что еще хуже, этот кто-то полезет своими потными ручками дописывать эту функцию
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.