скопгард :)
От: Кодт Россия  
Дата: 12.02.04 14:27
Оценка: 10 (2)
В очередной раз понял, как замечательно рулит скопгард. Чем и делюсь с уважаемым оллом.

Функция инициализации окна-формы (MFC), здоровенная, почему-то ничего не загрузила. Полез дебажить — а там оказывается, в случае некоторых ошибок делается просто return. И до финального UpdateData(false), естественно, не дошли.

Переписывать, с дикими ветвлениями — больно надо.
Делаем так:
class finally_t { }; // базовый класс

// исполнительный механизм - шаблонный класс
template<class Wnd>
class finally_update_data_t : public finally_t
{
  Wnd* wnd_;
  bool save_;
public:
  finally_update_data_t(Wnd* wnd, bool save) : wnd_(wnd), save_(save) { assert(wnd); }
  ~finally_update_data_t() { wnd_->UpdateData(save_); }
};
// и его порождающая функция
template<class Wnd>
finally_update_data_t<Wnd> finally_update_data(Wnd* wnd, bool save)
{ return finally_update_data_t<Wnd>(wnd,save); }

// макрос
#define FINALLY_DO(executor) finally_t& finally__##__LINE__ = executor
#define FINALLY_UPDATE_DATA(wnd,save) FINALLY_DO(finally_update_data(wnd,save))

выверт со ссылкой нужен, поскольку в макросе по-другому не получится завести переменную произвольного класса.

Осталось только включить FINALLY_UPDATE_DATA(this,false) где-нибудь в начале функции.

Идею я почерпнул в CUJ (www.cuj.com).
Перекуём баги на фичи!
Re: скопгард :)
От: What Беларусь  
Дата: 12.02.04 15:00
Оценка: 15 (2)
Здравствуйте, Кодт, Вы писали:

К>Идею я почерпнул в CUJ (www.cuj.com).


И у Мейрса такое тоже было.
Он ещё писал, что при использовании исключений такие штуки очень хороши.

By the way.
Писал я свои сигналы (boost::signals IMHO не везде отрабатывает корректно)
и был такой код (упрощённо):

template <typename TDoClass> struct C
{
    TDoClass m_DoClass;
    TDoClass::ReturnType operator()()
    {
        BeginDoSomething();
        TDoClass::ReturnType Ret = m_DoClass();
        EndDoSomething();
        return Ret;    
    }
};


Если TDoClass::ReturnType == void, то, естественно, не компилировалось.
Специализацию было писать лень (класс был очень большой).
Поэтому сделал вот так:

template <typename T> struct CFinilize
{
    T * m_pObj;
    CFinilize(T * pObj) : m_pObj(pObj)
    {
    }
    ~CFinilize()
    {
        m_pObj->EndDoSomething();
    }
};

template <typename TDoClass> struct C
{
    TDoClass m_DoClass;
    TDoClass::ReturnType operator()()
    {
        BeginDoSomething();
        CFinilize(this);
        return m_DoClass();
    }
};


И всё ок.
... << RSDN@Home 1.1.0 stable >>
Re[2]: скопгард :)
От: What Беларусь  
Дата: 12.02.04 15:04
Оценка:
Ошибся чуток: вместо TDoClass::ReturnType надо typename TDoClass::ReturnType.
... << RSDN@Home 1.1.0 stable >>
Re[2]: скопгард :)
От: Кодт Россия  
Дата: 12.02.04 15:16
Оценка:
Здравствуйте, What, Вы писали:

W>        return m_DoClass();
W>

если void TDoClass::operator()(), то VC6 ругается.
Перекуём баги на фичи!
Re[3]: скопгард :)
От: What Беларусь  
Дата: 12.02.04 15:23
Оценка:
Здравствуйте, Кодт, Вы писали:

К>если void TDoClass::operator()(), то VC6 ругается.


А VC 7.1 компилит
... << RSDN@Home 1.1.0 stable >>
Re: скопгард :)
От: Vamp Россия  
Дата: 12.02.04 15:40
Оценка:
К>В очередной раз понял, как замечательно рулит скопгард. Чем и делюсь с уважаемым оллом.
Я даже больше скажу. Скопгард частенько бывает приятнее, чем RAII.
Да здравствует мыло душистое и веревка пушистая.
Re: скопгард :)
От: folk Россия  
Дата: 13.02.04 02:32
Оценка: 16 (1) +1
Здравствуйте, Кодт, Вы писали:

К>В очередной раз понял, как замечательно рулит скопгард. Чем и делюсь с уважаемым оллом.


К>Функция инициализации окна-формы (MFC), здоровенная, почему-то ничего не загрузила. Полез дебажить — а там оказывается, в случае некоторых ошибок делается просто return. И до финального UpdateData(false), естественно, не дошли.


К>Переписывать, с дикими ветвлениями — больно надо.

К>Делаем так:
К>
К>class finally_t { }; // базовый класс

К>// исполнительный механизм - шаблонный класс
К>template<class Wnd>
К>class finally_update_data_t : public finally_t
К>{
К>  Wnd* wnd_;
К>  bool save_;
К>public:
К>  finally_update_data_t(Wnd* wnd, bool save) : wnd_(wnd), save_(save) { assert(wnd); }
К>  ~finally_update_data_t() { wnd_->UpdateData(save_); }
К>};
К>// и его порождающая функция
К>template<class Wnd>
К>finally_update_data_t<Wnd> finally_update_data(Wnd* wnd, bool save)
К>{ return finally_update_data_t<Wnd>(wnd,save); }

К>// макрос
К>#define FINALLY_DO(executor) finally_t& finally__##__LINE__ = executor
К>#define FINALLY_UPDATE_DATA(wnd,save) FINALLY_DO(finally_update_data(wnd,save))
К>

К>выверт со ссылкой нужен, поскольку в макросе по-другому не получится завести переменную произвольного класса.

Чтобы выверт со ссылкой был законным, это должна быть константная ссылка, т.к. она ссылается на rvalue.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.