Re: Ленивый ScopeGuard (не путать с голубцами!)
От: TepMuHyc  
Дата: 23.09.03 10:02
Оценка: 33 (2)
Здравствуйте, MaximE, Вы писали:

ME>Решение — паразитировать на boost::bind. Преимущество данного решения в том, что не нужно реализовывать кучу байндеров вручную, причем для разных calling conventions, — все уже давно реализовано в boost::bind.


Вумное и вполне логичное решение — мои аплодисменты.
Вот только есть вопросец: а зачем делать так ?
template<class R, class F, class A>
class scope_guard_impl : public scope_guard_base
{
private:
    typedef boost::_bi::bind_t<R, F, A> binder; //<-- вот так?


Не проще ли сделать вот так?
template<class F>
class scope_guard_impl : public scope_guard_base
{
private:
    typedef F binder; //<-- вот так?


Ведь все что требуется от типа binder, это чтобы он поддерживал выражение " rollback_() "; То есть, чтобы он был функтором без параметров. Лично я не никакого вижу смысла ограничивать выбор функторов только функторами базирующимися на шаблоне boost::_bi::bind_t .

Функция make_guard в этом случае будет выглядеть так:

template<class F>
inline detail::scope_guard_impl<F> make_guard(const F& b)
{
    return detail::scope_guard_impl<F>(b);
}


Так это будет работать с любыми байндерами и любыми функторами которые не требуют параметров.
И, самое главное, никаких зависимостей от boost или еще какой библиотеки

Что же касается неудобства написания выражения scope_guard g = make_guard(boost::bind( ............. )), то эта проблема никуда не делась

Вариантов ее решения вижу два:
— Или макросы, как предложено Александреску (но имхо это коряво, да и клэшаться они любят, падлы)
— Или писать туеву хучу оверлоадов для make_guard() как это сделано для функции boost::bind() (см. файлы boost/bind/bind_cc.hpp и boost/bind/bind_mf_cc.hpp)

Имхо, легче лишний раз написать "make_guard(boost::bind...."
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: Ленивый ScopeGuard (не путать с голубцами!)
От: MaximE Великобритания  
Дата: 23.09.03 10:10
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

[]

TMH>Не проще ли сделать вот так?

TMH>
TMH>template<class F>
TMH>class scope_guard_impl : public scope_guard_base
TMH>{
TMH>private:
TMH>    typedef F binder; //<-- вот так?
TMH>


TMH>Ведь все что требуется от типа binder, это чтобы он поддерживал выражение " rollback_() "; То есть, чтобы он был функтором без параметров. Лично я не никакого вижу смысла ограничивать выбор функторов только функторами базирующимися на шаблоне boost::_bi::bind_t .


Да, точно. Просто меня точила мысль именно с boost::bind, а про другие функторы я и не думал

TMH>Функция make_guard в этом случае будет выглядеть так:


TMH>
TMH>template<class F>
TMH>inline detail::scope_guard_impl<F> make_guard(const F& b)
TMH>{
TMH>    return detail::scope_guard_impl<F>(b);
TMH>}
TMH>


TMH>Так это будет работать с любыми байндерами и любыми функторами которые не требуют параметров.

TMH>И, самое главное, никаких зависимостей от boost или еще какой библиотеки

Отлично!

TMH>Что же касается неудобства написания выражения scope_guard g = make_guard(boost::bind( ............. )), то эта проблема никуда не делась


TMH>Вариантов ее решения вижу два:

TMH>- Или макросы, как предложено Александреску (но имхо это коряво, да и клэшаться они любят, падлы)
TMH>- Или писать туеву хучу оверлоадов для make_guard() как это сделано для функции boost::bind() (см. файлы boost/bind/bind_cc.hpp и boost/bind/bind_mf_cc.hpp)

TMH>Имхо, легче лишний раз написать "make_guard(boost::bind...."


Я пришел к тому же выводу .
Re[2]: Ленивый ScopeGuard (не путать с голубцами!)
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 23.09.03 13:38
Оценка:
Здравствуйте, TepMuHyc, Вы писали:
TMH>Что же касается неудобства написания выражения scope_guard g = make_guard(boost::bind( ............. )), то эта проблема никуда не делась

TMH>Вариантов ее решения вижу два:

TMH>- Или макросы, как предложено Александреску (но имхо это коряво, да и клэшаться они любят, падлы)
TMH>- Или писать туеву хучу оверлоадов для make_guard() как это сделано для функции boost::bind() (см. файлы boost/bind/bind_cc.hpp и boost/bind/bind_mf_cc.hpp)

TMH>Имхо, легче лишний раз написать "make_guard(boost::bind...."


Есть третий вариант с использованием auto_ptr или boost::function но оно слишком тяжеловесно. В принципе, там где есть alloca() можно наверно как-нибудь извратится и обойтись без динамического выделения памяти, но ...
Re: [boost] ScopeGuard
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 24.09.03 13:38
Оценка: 1 (1)
Здравствуйте, MaximE, Вы писали:

ME>Думаю, многие знакомы с ScopeGuard.


ME>Мне очень понравилась его идея, но только он не привел исходников — видимо, по его мнению, любой желающий может сам реализовать эту кучу байндеров.


ME>Последнее время мне много приходится работать с legacy кодом, поэтому проблема стала для меня крайне острой.


ME>Будучи ленивым по натуре, я хотел использовать что-либо готовое. Но готового ScopeGuard я не мог найти.


ME>Решение — паразитировать на boost::bind. Преимущество данного решения в том, что не нужно реализовывать кучу байндеров вручную, причем для разных calling conventions, — все уже давно реализовано в boost::bind.


http://lists.boost.org/MailArchives/boost/msg52712.php
Re: Ленивый ScopeGuard (не путать с голубцами!)
От: jazzer Россия Skype: enerjazzer
Дата: 24.09.03 13:50
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Думаю, многие знакомы с ScopeGuard.


ME>Мне очень понравилась его идея, но только он не привел исходников — видимо, по его мнению, любой желающий может сам реализовать эту кучу байндеров.


ME>Последнее время мне много приходится работать с legacy кодом, поэтому проблема стала для меня крайне острой.


ME>Будучи ленивым по натуре, я хотел использовать что-либо готовое. Но готового ScopeGuard я не мог найти.


ME>Решение — паразитировать на boost::bind. Преимущество данного решения в том, что не нужно реализовывать кучу байндеров вручную, причем для разных calling conventions, — все уже давно реализовано в boost::bind.


<cool code skipped>

А еще можно попробовать присосаться заодно и к wrapper'у, предложенному Строуструпом, для обертки функций пре- и постдействиями.
Тогда вообще мощный механизм получится... Надо пообмозговать...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: [boost] ScopeGuard
От: MaximE Великобритания  
Дата: 24.09.03 13:50
Оценка:
Здравствуйте, alnsn, Вы писали:

A>http://lists.boost.org/MailArchives/boost/msg52712.php


I took the ScopeGuard implementation by Andrei Alexandrescu and
reimplemented it using Boost.Function and Boost.Bind. I was able to
implement it with a single class and one helper function per supported
signature. It is really useful. If anyone is interested, I can send it to
them or post it to the list.

John Sheehan


Должна и с boost::lambda работать.
Re: Ленивый ScopeGuard (не путать с голубцами!)
От: MaximE Великобритания  
Дата: 25.09.03 05:58
Оценка:
Здравствуйте, MaximE, Вы писали:

[]

Важное исправление:

Необходимо обязательно добавить конструктор копирования с передачей владения, иначе после копирования деструкторы копий и оригиналов гардов выполнят roll_back_ более одного раза.

class scope_guard_base
{
public:
    void dismiss() const
    {
        do_rollback_ = false;
    }

protected:
    scope_guard_base(const scope_guard_base& other)
        :    do_rollback_(other.do_rollback_)
    {
        other.dismiss();
    }

    scope_guard_base()
        :    do_rollback_(true)
    {}

    mutable bool do_rollback_;
};
Re: Не устаем лениться...
От: folk Россия  
Дата: 02.10.04 02:39
Оценка: 30 (1)
Создатели boost/bind поместили определения шаблонов bind() в отдельные файлы и реюзают их для различных calling conventions с помощью препроцессора. Благодаря этому мы можем сделать следующий идеологически верный шаг в ленивой реализации scope_guard.

Грубо говоря, делаем что-то вроде #define boost::bind make_guard, включаем файлы с определением bind, и затем #undef boost::bind. Таким вместо того чтобы писать так
scope_guard g = make_guard( boost::bind( f, arg ) );
теперь можно писать так
scope_guard g = make_guard( f, arg );

Реализованы make_guard-байндеры для свободных функций и для функций членов, константных и неконстантных. Поддержка calling conventions такая же как в boost::bind. Make_guard для функциональных объектов не реализован, ну да не больно оно надо для скопгардов.

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

Вот обновленный исходник scope_guard.h:
////////////////////////////////////////////////////////////////////////////////////////////////
// scope_guard.hpp

#pragma once
#include <boost/bind.hpp>

////////////////////////////////////////////////////////////////////////////////////////////////

namespace util {

////////////////////////////////////////////////////////////////////////////////////////////////

namespace detail {

////////////////////////////////////////////////////////////////////////////////////////////////

class scope_guard_base
{
 public:
    void dismiss() const
    {
        do_rollback_ = false;
    }

 protected:
    scope_guard_base(const scope_guard_base& other)
        :    do_rollback_(other.do_rollback_)
    {
        other.dismiss();
    }

    scope_guard_base()
        :    do_rollback_(true)
    {}

    mutable bool do_rollback_;
};

////////////////////////////////////////////////////////////////////////////////////////////////

template<class R, class F, class A>
class scope_guard_impl : public scope_guard_base
{
 public:
    scope_guard_impl(F f, A const& a)
        :    rollback_(f, a)
    {}

    ~scope_guard_impl()
    {
        if(do_rollback_)
            rollback_();
    }

 private:
    boost::_bi::bind_t<R,F,A> rollback_;
};

////////////////////////////////////////////////////////////////////////////////////////////////

} // namespace detail

////////////////////////////////////////////////////////////////////////////////////////////////

typedef detail::scope_guard_base const& scope_guard;

////////////////////////////////////////////////////////////////////////////////////////////////
//  create make_guard() definitions by preprocessing boost::bind() sources

namespace detail {

using boost::_bi::list0;
using boost::_bi::list_av_1;
using boost::_bi::list_av_2;
using boost::_bi::list_av_3;
using boost::_bi::list_av_4;
using boost::_bi::list_av_5;
using boost::_bi::list_av_6;
using boost::_bi::list_av_7;
using boost::_bi::list_av_8;
using boost::_bi::list_av_9;

} // namespace detail

#undef BOOST_BIND   // it seems like boosters forgot about it

#define BOOST_BIND  make_guard
#define _bi         detail
#define bind_t      scope_guard_impl
#define _mfi        boost::_mfi

////////////////////////////////////////////////////////////////////////////////////////////////
//  quotation from boost/bind.hpp
//  Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
//  Copyright (c) 2001 David Abrahams

// function pointers

#define BOOST_BIND_CC
#define BOOST_BIND_ST

#include <boost/bind/bind_cc.hpp>

#undef BOOST_BIND_CC
#undef BOOST_BIND_ST

#ifdef BOOST_BIND_ENABLE_STDCALL

#define BOOST_BIND_CC __stdcall
#define BOOST_BIND_ST

#include <boost/bind/bind_cc.hpp>

#undef BOOST_BIND_CC
#undef BOOST_BIND_ST

#endif

#ifdef BOOST_BIND_ENABLE_FASTCALL

#define BOOST_BIND_CC __fastcall
#define BOOST_BIND_ST

#include <boost/bind/bind_cc.hpp>

#undef BOOST_BIND_CC
#undef BOOST_BIND_ST

#endif

#ifdef BOOST_BIND_ENABLE_PASCAL

#define BOOST_BIND_ST pascal
#define BOOST_BIND_CC

#include <boost/bind/bind_cc.hpp>

#undef BOOST_BIND_ST
#undef BOOST_BIND_CC

#endif

// member function pointers

#define BOOST_BIND_MF_NAME(X) X
#define BOOST_BIND_MF_CC

#include <boost/bind/bind_mf_cc.hpp>

#undef BOOST_BIND_MF_NAME
#undef BOOST_BIND_MF_CC

#ifdef BOOST_MEM_FN_ENABLE_STDCALL

#define BOOST_BIND_MF_NAME(X) X##_stdcall
#define BOOST_BIND_MF_CC __stdcall

#include <boost/bind/bind_mf_cc.hpp>

#undef BOOST_BIND_MF_NAME
#undef BOOST_BIND_MF_CC

#endif

#ifdef BOOST_MEM_FN_ENABLE_FASTCALL

#define BOOST_BIND_MF_NAME(X) X##_fastcall
#define BOOST_BIND_MF_CC __fastcall

#include <boost/bind/bind_mf_cc.hpp>

#undef BOOST_BIND_MF_NAME
#undef BOOST_BIND_MF_CC

#endif

//  end quotation boost/bind.hpp ///////////////////////////////////////////////////////////////

#undef BOOST_BIND
#undef _bi
#undef bind_t
#undef _mfi

////////////////////////////////////////////////////////////////////////////////////////////////

} // namespace util

////////////////////////////////////////////////////////////////////////////////////////////////


ЗЫ И кто там говорил, что в бустовские заголовки в самом бусте включаются только так #include "some", а не так #include <some> ?
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.