Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: шаблон raii замены указателя на фукнцию  (Прочитано 32571 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
Mayor
Специалист

ru
Offline Offline

« : 12-09-2009 06:57 » 

шаблон raii замены указателя на фукнцию

допустим имеется набор указателей на функции разных типов и существует потребность временно, локально подменять функцию в указателе:

pf old=set_pf(&new_func);
// может случиться stack unwind
set_pf(old); // должна по любому выполниться перед выходом из функции

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

Записан

1n c0de we trust
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 12-09-2009 07:10 » 

Mayor, А зачем это надо? На настояшем проекте за такие финты сразу бы выгнали, без дополнительных объяснений. Слишком опасный код. Что мешает пользователю вызвать функцию не стеми аргументами?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mayor
Специалист

ru
Offline Offline

« Ответ #2 : 12-09-2009 08:53 » 

как это не с теми аргументами?

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

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

если в коде отсутвии виртуального деструктора считается за ошибку - то нефиг туда с шаблонами лезть

если в требованиях указано - отсутсвие знания линукс, то нефиг упоминать что ты им пользовался

по сабжу, задачка учебная и спорить тут опасный - не опасный бесмысленно, пока не заценишь шаблон на конкретных примерах
Записан

1n c0de we trust
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 12-09-2009 09:09 » 

Применяй тип void *,  Он все вытерпет. А вызовы переопределяй в функциях.
Код:
void set_pf(type1 func);
void set_pf(type2 func);
void set_pf(type3 func);
Также скачай в сети библиотеку Loki http://sourceforge.net/projects/loki-lib/ . Эта библиотека была написана Андреем Александреску  и хорошо разобрана в его книге. Там тшательно смотри, как он реализовал функторы.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mayor
Специалист

ru
Offline Offline

« Ответ #4 : 12-09-2009 10:32 » 

похоже мы друг друга не поняли:
Код:
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
void glob(int i) { cout<<"in global "<<i<<endl; }
void loc(int i) { cout<<"in local "<<i<<endl; }
typedef void (*f1)(int);
f1 ff1=glob;
f1 set_ff1(f1 a) {
f1 b=ff1;
ff1=a;
return b;
}
class stc {
f1 old;
public:
stc(f1 ff) { old=set_ff1(ff); }
~stc() { set_ff1(old); }
};
struct err {};
void test() throw (err) try {
f1 a=set_ff1(loc);
ff1(3);
cout<<"in test"<<endl;
int i=0;
cin>>i;
if (i>4) throw err();
ff1(i);
set_ff1(a);
}
catch(err ) {
cout<<"catcha "<<endl;
}
void test1() throw (err) try {
stc l(loc);
ff1(3);
cout<<"in test1 "<<endl;
int i=0;
cin>>i;
if (i>4) throw err();
ff1(i);
}
catch(err ) {
cout<<"catcha test1 "<<endl;
}
/* лажа с передачей адреса фукнции в параметре
template<class T> class stct {
T old;
public:
stct(T ff,T (*fff)(T)) { old=fff(ff); }
~stct() { set_(old); }
};
void test2() throw (err) try {
//stc l(loc);
stct<ff1> l(loc,set_ff1);
ff1(3);
cout<<"in test1 "<<endl;
int i=0;
cin>>i;
if (i>4) throw err();
ff1(i);
}
catch(err ) {
cout<<"catcha test1 "<<endl;
}
*/
int main() {
ff1(1);
//test();
test1();
cout<<"hello"<<endl;
ff1(4);
}

в коде тест ведет себя не правильно - тк при выходе из нее есть вероятность, что измененный ей глобальный указатель не вернется к прежнему значению
test1 работает правильно - через raii class stc полюбому происходит востановление глобального указателя
сейчас у меня не получается написать шаблон, который можно будет вставить в test1,test2 и тд : в параметрах которого передается устанавливающая фукнция и тип указателя  на фукнцию, а в аргуметах конструктора - сам указатель

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


1h later:

удалось переписать шаблон, так чтобы он скомпилировался:
Код:
template<class T,T(*getval)(T)> class stct {
T old;
public:
stct(T ff) throw() {
old=getval(ff);
        }
~stct() throw() {
getval(old);
}
};
void test2() throw (err) try {
stct<f1,set_ff1> l(loc1);
ff1(3);
cout<<"in test2 "<<endl;
int i=0;
cin>>i;
if (i>4) throw err();
ff1(i);
}
catch(err ) {
cout<<"catcha test2 "<<endl;
}

вроде бы даже правильно работает, только как и говорил финч во 2м посте, все выглядит криво и непонятно ...

зы как-нибудь можно превратить вызов stct<f1,set_ff1> l(loc1) в    stct<set_ff1> l(loc1) ?
или дополнительное указание типа аргумента\возвращаемого значения из фукнции создает защиту "от дурака" ?
« Последнее редактирование: 12-09-2009 11:25 от Mayor » Записан

1n c0de we trust
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 12-09-2009 18:28 » 

Хотелось бы прояснить одну вещь. А что здесь названо RAII? Я не вижу никакого ресурса. Ведь функцию сложно назвать отдельным выделяемым ресурсом?
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #6 : 13-09-2009 04:16 » 

Хотелось бы прояснить одну вещь. А что здесь названо RAII? Я не вижу никакого ресурса. Ведь функцию сложно назвать отдельным выделяемым ресурсом?

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

Mayor, А зачем это надо? На настояшем проекте за такие финты сразу бы выгнали, без дополнительных объяснений. Слишком опасный код. Что мешает пользователю вызвать функцию не стеми аргументами?

итак, независимо от того как ты пишешь на с++, у нас есть глобаные указатели на фукнцию, пусть это будут: callback, event handle, иже с ними - которые являются неотъемлимой частью библиотеки инициализирующей с++ приложение ... и возможно у некоторых со временем будет возникать необходимость насоздавать новых глобальных указателей - но это уже тема отдельного разговора

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

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

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

зы с первыми 2мя ничего не сделать, тут все зависит от криворукости кодера, ему в принципе без разницы где накосячить:
function_type old_pf=set_function(new_pointer);
// или
raii_function_set<function_type,set_function> h(new_pointer);

зыы может быть это опять назовут антипатерном, но я при текущем уровне знаний, все равно не пойму почему
« Последнее редактирование: 13-09-2009 10:15 от Вад » Записан

1n c0de we trust
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 13-09-2009 10:23 » 

Теперь я понял. Только это не raii. Вот если бы у тебя контролировалось время жизни функции - это было бы raii. Скажем, в конструкторе загружалась бы dll-библиотека с функцией, а в деструкторе выгружалась бы. А раз ты никак не контролируешь время жизни ресурса - это не raii.

Я бы назвал это динамической настройкой диспетчеризации. Только непонятно, зачем указатель на функцию тогда инкапсулировать в объект. Если только - действительно, сопровождать доступ к функции какими-то сторонними эффектами типа записи логов.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #8 : 13-09-2009 12:38 » 

Mayor, Я все равно не понимаю, для чего тебе  эти финты нужны. Причины:
1) Нарушается сама идеология классов. Вдруг они начинают регулировать глобальные переменные. При этом они не имеют полного контроля над переменной.
2) Раз подменяеш свою функцию локально, почему бы ее локально и не использовать напрямую?
3) Твой пример в многопоточном приложении сразу поплывет.

В контекста, того что сказал Вад, насчет временного хранения Dll. Это мне кажется вполне логично. Но в его примере всё будет хранится локально, в самом классе.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mayor
Специалист

ru
Offline Offline

« Ответ #9 : 13-09-2009 14:23 » 

Finch, 2 локально я вызывал фукнции только для тестирования, через глобальный указатель по идее фукнции будут вызываться из неизвестного участка кода

Вад, указатель инкапсулируется на случай проброса исключения
Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #10 : 14-09-2009 03:02 » 

Mayor, а теперь дружно думаем о многопоточном коде
Записан

Странно всё это....
sss
Специалист

ru
Offline Offline

« Ответ #11 : 14-09-2009 05:31 » 

LogRus, я честно признаюсь, перечитал раза 4 и ничего не понял. Что надо автору темы? Перехватить исключение и вернуть старое значение? Зачем тогда такой огород?
Записан

while (8==8)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 14-09-2009 05:44 » 

sss, автор темы "понимал толк в извращениях" (с)  )))
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 14-09-2009 06:03 » 

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

Странно всё это....
sss
Специалист

ru
Offline Offline

« Ответ #14 : 14-09-2009 06:15 » 

Может быть это попытка динамически окружить любую устанавливаемую функцию дополнительным обработчиком? Но тогда лучше это делать в том месте, где вызывается переустанавливаемая  функция.  Это всё задачи объекта вызывающего CALLBACK.
Записан

while (8==8)
Mayor
Специалист

ru
Offline Offline

« Ответ #15 : 26-09-2009 10:02 » 

sss, эээ если ты подразумеваешь под переустанавливаемой функцией glob,loc -то вызываться она может и из сторонней библиотеки
Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #16 : 28-09-2009 06:50 » 

и снова шум
не умеешь пользоваться русским, пользуйся кодом, ИМХО проще понять твой код, чем твой смысловой шум с непонятным подтекстом.
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #17 : 21-12-2009 17:50 » new

А чем стратегия не подходит?
Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #18 : 22-12-2009 04:36 » 

lapulya, отличный вопрос Улыбаюсь
давай конкретней обрисуй ситуацию и продолжим диспут
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #19 : 22-12-2009 07:19 » 

LogRus, немного не понял кому ты предложил конкретнее обрисовать ситуацию мне или топикстартеру. Если мне, то я спрашивал о паттерне стратегия.
Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #20 : 22-12-2009 08:00 » 

lapulya, вопрос к тебе Улыбаюсь , как именно ты предлагаешь использовать стратегии для конкретной задачи?
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #21 : 22-12-2009 14:53 » 

так... давайте прежде чем будем структурировать определился правильно ли я все понимаю...

Mayor, я правильно понимаю, что следующий шаблон, который есть упрощенный твой шаблон (при условии, что set_ff1 одна и не меняется)
Код:
template<class T> class stct
{
T old;
public:
stct(T ff) throw()
{
old=set_ff1(ff);
    }
~stct() throw()
{
set_ff1(old);
}
};

void test2() throw (err)
{
try
{
stct<f1> l(loc);
ff1(3);
cout<<"in test2 "<<endl;

int i=0;
cin>>i;

if (i>4) throw err();
ff1(i);
}
catch(err )
{
cout<<"catcha test2 "<<endl;
}
}
,

это то, что тебе надо?

Если да, то ща бум структурировать, но для начала вопрос, зачем это надо? Какая прикладная задача решается? 
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #22 : 22-12-2009 15:01 » 

собственно вопрос такой, что в данном случае является клиентом main или test2?
Если делать клиентом test2 эээ, то не ясна цель, поскольку test2 точно знает, что надо вызвать loc! Может его вызвать на прямую, стало быть клиент main, правильно?
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #23 : 22-12-2009 15:08 » 

если нужны разные функции замены (set_ff1), то можно так
Код:
typedef void (*f1)(int);
typedef f1 (*f11)(f1);

template<class T> class stct
{
T old;
f11 change;
public:
stct(T ff, f11 _change) throw()
{
change = _change;
old=change(ff);
    }
~stct() throw()
{
change(old);
}
};

void test2() throw (err)
{
try
{
stct<f1> l(loc, set_ff1);

...
Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #24 : 23-12-2009 04:30 » 

lapulya, так, а где стратегии? Улыбаюсь

я пока вижу только стратегию синхронизации, как вариант развития
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #25 : 23-12-2009 12:40 » 

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

С уважением Lapulya
Mayor
Специалист

ru
Offline Offline

« Ответ #26 : 23-12-2009 17:33 » 

ну если вспомнить с чего все началось:

1 нашел я где то упоминание\описание raii, честно говоря, я во всех этих синглетонах, фабриках, виртуальных конструкторах ни бум-бум - начал изобретать велосипед: те реализовывать raii в том плане как я понял из его описания

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

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

а сейчас вообще не знаю, зачем этот raii вообще нужен Улыбаюсь





Записан

1n c0de we trust
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #27 : 23-12-2009 18:07 » 

Mayor, Эээээ т.е. реальной прикладной задачи нет? Вот ты тогда замутил... ты бы формулировал вопрос нипа нах нужен такой-то паттерн и ответ получит бы в первом же посте (или RTFM, ну или рассказали бы Улыбаюсь )

по гарду, тебе ж писали он нужен для охраны ресурса, ну например, открытый файл на запись. Допустим несколько потоков могут писать в один и тот же файл. Если они это будут делать одновременно, то будет жопа. Поэтому нада чтоб они это делали последовательно, стало быть делаем гард, ну например:
конструктор -  открываем критическую секцию, отрываем файл на запись;
деструктор - закрываем файл, закрываем критическую секцию.
создаем гард на стеке и в области жизни гарда пишем в файл (ну как пример)

Все просто.

В прочем гарды бывают разные, могут использоваться не для охраны, а например, для гарантии освобождения ресурса (конструктор - открываем файл, деструктор - закрываем и т.д.)
« Последнее редактирование: 23-12-2009 18:30 от lapulya » Записан

С уважением Lapulya
Mayor
Специалист

ru
Offline Offline

« Ответ #28 : 24-12-2009 05:12 » 

тут тоже самое и получилось:

запоминаем значение указателя в конструкторе и перезаписываем его
восстанавливаем значение указателя в деструкторе

в принципе работает при структурном подходе, единственное, что тк не умею работать с шаблонами - написано криво

а при ООП начинаются траблы: если делать через встроенный объект, то каллбек перехватится до того как создан объект, если создавать его в конструкторе, то при исключении в нем старое значение указателя не восстановится

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

1n c0de we trust
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #29 : 24-12-2009 16:00 » 

Mayor, Тип через аргумент передать нельзя

Если хочешь вариант решения проблем, то проблему надо до нас донести, пока ты доносишь до нас свое решение нечта (это нечто мне лично пока не понятно) и говоришь, что оно тебя не устраивает. На основании этих данных помочь тебе очень сложно Улыбаюсь\

Я так понимаю, что мой вариант (последний или предпоследний), твою проблему не решил или решил?
« Последнее редактирование: 24-12-2009 16:05 от lapulya » Записан

С уважением Lapulya
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines