Оптимизация кода
От: smj  
Дата: 08.04.09 07:19
Оценка:
Здравствуйте,

помогите кто чем может ) с оптимизацией кода.
Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса. На данный момент ф-я перебора выглядит так:
class CFoo
{
 template <typename TCallee, HRESULT (TCallee::*pFunc)(CContainer*, CRecord*)> 
 HRESULT Iterate(TCallee* pCallee, /* ещё пара параметров */ )
 {
  подготовка, создание контейнера, заполнение и т.д.
  
  итерация по элементам контейнера, вызов callback
  for (...)
  {
    hRet = (pCallee->*pFunc)(pContainer, pContainer[i]);
  }

  очистка
 }
}

есть ещё вариант, где callback ф-я имеет дополнительный параметр:
class CFoo
{
 template <typename TCallee, typename TParam, HRESULT (TCallee::*pFunc)(CContainer*, CRecord*, TParam)>
 HRESULT Iterate(TCallee* pCallee, TParam pParam /* ещё пара параметров */ )
 {
  здесь внутри всё то же самое, единственно что меняется это вызов callback
  for (...)
  {
    hRet = (pCallee->*pFunc)(pContainer, pContainer[i], pParam);
  }
 }
}

Понятно, что ещё возможны варианты с callback'ами const типа:
HRESULT (TCallee::*pFunc)(CContainer*, CRecord*) const
HRESULT (TCallee::*pFunc)(CContainer*, CRecord*, TParam) const


и каждый раз единственное изменение это строка вызова, то есть 99% кода дублируется.

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

Есть другая идея, только с реализацией что-то никак. Сделать одну единтственную ф-ю, которая занимается перебором, и вызов callback'a как-то (как ?) настраивать в зависимости от обстоятельств.

Может быть есть и другие, лучшие или очевидные варианты решения проблемы.

Заранее благодарен за идеи и комментарии )
Re: Оптимизация кода
От: zaufi Земля  
Дата: 08.04.09 09:23
Оценка:
Здравствуйте, smj, Вы писали:

smj>Здравствуйте,


smj>помогите кто чем может ) с оптимизацией кода.

smj>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса.
ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:
class CFoo
{
 template <typename Func> 
 HRESULT Iterate(Func f, /* ещё пара параметров */ )
 {
  подготовка, создание контейнера, заполнение и т.д.
  
  итерация по элементам контейнера, вызов callback
  for (...)
  {
    hRet = f(pContainer, pContainer[i]);
  }

  очистка
 }
}

функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров...

CFoo obj;

// call function w/o aux params
obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));

// call function w/ one aux param
SomeParam p1;
obj.Iterate(boost::bind(&another_obj::member_func_with_param, _1, _2, p1));

// call function w/ two aux params
SomeParam p1;
SomeParam2 p2;
obj.Iterate(boost::bind(&another_obj::member_func_with_2_params, _1, _2, p1, p2));


альтернативный вариант состоит в написании итератора (совместимого с STLным) для твоего контейнера (используя для простоты например библиотечку boost::iterator)... в результате получишь возможность сувать свои итераторы в std:: алгоритмы...

PS: также луче избавиться от передачи контейнера в callback -- по хорошему все что должно быть нужно этой функции это элемент контейнера (ну или итератор на него)...
Re: Оптимизация кода
От: LaptevVV Россия  
Дата: 08.04.09 09:46
Оценка:
Здравствуйте, smj, Вы писали:

smj>Может быть есть и другие, лучшие или очевидные варианты решения проблемы.

А паттерн Шаблонный метод не подойдет?
В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте.
Два наследника по-разному реализуют этот метод.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Оптимизация кода
От: smj  
Дата: 08.04.09 10:56
Оценка:
Здравствуйте, LaptevVV, Вы писали:

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


smj>>Может быть есть и другие, лучшие или очевидные варианты решения проблемы.

LVV>А паттерн Шаблонный метод не подойдет?
LVV>В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте.
LVV>Два наследника по-разному реализуют этот метод.

идея интересная, честно говоря, не совсем себе представляю как всё это дело увязать с шаблонами, надо будет поэкспериментировать. Видимо придётся всего наследника как класс параметризировать, и соответсвенно на каждый типа callback'а писать свой класс.
Re[2]: Оптимизация кода
От: smj  
Дата: 08.04.09 11:06
Оценка:
Здравствуйте, zaufi, Вы писали:

smj>>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса.

Z>ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:

Ага, это по идее то что надо.

Z>функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров...

Z>obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));

Буста к сожалению нет и не предвидется, поэтому вместо "на лету" придётся кустарным методом конфигурировать функтор, это не столь трагично.
Re[3]: Оптимизация кода
От: Аноним  
Дата: 08.04.09 11:34
Оценка:
Здравствуйте, smj, Вы писали:

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


smj>>>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса.

Z>>ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:

smj>Ага, это по идее то что надо.


Z>>функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров...

Z>>obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));

smj>Буста к сожалению нет и не предвидется, поэтому вместо "на лету" придётся кустарным методом конфигурировать функтор, это не столь трагично.


functional есть в большинстве компиляторов в std::tr1::
Re[3]: Оптимизация кода
От: LaptevVV Россия  
Дата: 08.04.09 12:41
Оценка:
Здравствуйте, smj, Вы писали:

smj>>>Может быть есть и другие, лучшие или очевидные варианты решения проблемы.

LVV>>А паттерн Шаблонный метод не подойдет?
LVV>>В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте.
LVV>>Два наследника по-разному реализуют этот метод.

smj>идея интересная, честно говоря, не совсем себе представляю как всё это дело увязать с шаблонами, надо будет поэкспериментировать. Видимо придётся всего наследника как класс параметризировать, и соответсвенно на каждый типа callback'а писать свой класс.

Шаблоны С++ здесь не обязательно использовать. Вот элементарный пример паттерна Шаблоннный метод:
-------------Базовый абстрактный класс
class Application
{   bool isDone;
  protected:
    virtual void Initialize() = 0;
    virtual void Terminate() = 0;
    virtual void Work() = 0;
    virtual void setDone() { isDone = true; }
    virtual bool Done()    { return isDone; }
  public:
    Application(): isDone( false ) {}
    void run()                                     // шаблонный метод
    {   Initialize();                              // типовая инициализация
        while( !Done() )                           // условие завершения    
        { 
           Work();                                 // выполнение нужных действий
        }
        Terminate();                               // завершение 
    }
};
------------------Наследник
class Program: public Application
{   int k;        
  protected:
    virtual void Initialize()                         // инициализация
    {   cout << "Initialize()" << endl; }
    virtual void Terminate()                          // завершение
    {   cout << "Terminate()" << endl; }
    virtual void Work();                              // основные действия
  public: 
    Program( int n ): k( n ) {} 
};
void Program::Work()                              // основные действия
{   for( int i = 0; i < k; ++i ) cout << "Work() = " << k << endl;
    setDone();                                    // завершение цикла в run
}
-----------Использование:
Application *pA = new Program( 111 );
pA -> run();
Program App( 10 );
App.run();

Можно в базовом классе оставить один абстрактный метод run(), который вызывается в общем коде.
А наследники реализуют его по разному. Тогда виртуальность сработает сама.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.