как отловить вызов ф-ции
От: piAnd Россия  
Дата: 02.10.06 18:27
Оценка:
Привет всем! Подскажите хотяб идею для решения вот такой проблемы.

//определение
class C1{
public:
   void foo(){/*...*/}
};
//и
template <typename T>
class C2{
public:
   C2(T &Src):Ref(Src){}//в Ref храним ссылку на заданный объект
   void foo(){/*...*/}
   T &Ref;
};

//в главном cpp:
C1 c1;
C2<C1> c2_1(с1);
C2<C1> c2_2(с1);


проблема в том, чтобы при каждом вызове c2_x.foo() мы как-то должны знать, что уже вызывалась c1.foo().
Можно добавить в C1 и C2 флаг, который бы менялся в c1.foo() и сигнализировал об ее запуске, а в c2_x.foo() шло бы сравнение старого флага, хранящегося в c2_x и флага из Ref. Но что если мы запустим c1.foo() столько раз, чтобы флаг вернулся в исходное состояние, и c2_x.foo() обломится (если использовать в качестве флага перечислимый тип). Кто што может предложить? Спась.
Re: как отловить вызов ф-ции
От: _nn_ www.nemerleweb.com
Дата: 02.10.06 18:54
Оценка:
Здравствуйте, piAnd, Вы писали:

A>Привет всем! Подскажите хотяб идею для решения вот такой проблемы.


A>
A>//определение
A>class C1{
A>public:
A>   void foo(){/*...*/}
A>};
A>//и
A>template <typename T>
A>class C2{
A>public:
A>   C2(T &Src):Ref(Src){}//в Ref храним ссылку на заданный объект
A>   void foo(){/*...*/}
A>   T &Ref;
A>};

A>//в главном cpp:
A>C1 c1;
A>C2<C1> c2_1(с1);
A>C2<C1> c2_2(с1);
A>


A>проблема в том, чтобы при каждом вызове c2_x.foo() мы как-то должны знать, что уже вызывалась c1.foo().

A>Можно добавить в C1 и C2 флаг, который бы менялся в c1.foo() и сигнализировал об ее запуске, а в c2_x.foo() шло бы сравнение старого флага, хранящегося в c2_x и флага из Ref. Но что если мы запустим c1.foo() столько раз, чтобы флаг вернулся в исходное состояние, и c2_x.foo() обломится (если использовать в качестве флага перечислимый тип). Кто што может предложить? Спась.

А чем не устраивает вызвать foo в C2::foo ?
Защита от повторного выбора делается элементарно:

void C1::foo()
{
 static bool flag;
 if(!flag)
 {
  flag = true;
  // делаем что надо 
 }
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 02.10.06 19:17
Оценка:
Здравствуйте, _nn_, Вы писали:

__>А чем не устраивает вызвать foo в C2::foo ?

дык C1::foo и C2::foo совершенно разные
__>Защита от повторного выбора делается элементарно:
__>
__>void C1::foo()
__>{
__> static bool flag;
__> if(!flag)
__> {
__>  flag = true;
__>  // делаем что надо 
__> }
__>}
__>

в этом и вопрос, если непредупредив C2::foo, вызываю C1::foo 2 раза и возвращаюсь на круги своя, а это . А предупредить C2::foo из C1::foo никак нельзя, ибо C2::foo вообще может не быть, классы то совершенно несвязаны иерархически, и никаких предположений об C2 в C1 не делается. В этом трабл.
Re[2]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 02.10.06 20:44
Оценка:
Здравствуйте, _nn_, Вы писали:

А вообще я ошибочно поставил вопрос.
Каждый из экземпляров c2_x может быть создан в любой момент, поэтому один булевый флаг на всех и не катит. В том числе не катит и целочисленный, по причине ограниченности его диапазона. + C1 ничего не знает об C2. Поэтому как-то должен сам предоставлять некий метод или что-то еще...
Re[3]: как отловить вызов ф-ции
От: _nn_ www.nemerleweb.com
Дата: 02.10.06 20:57
Оценка:
Здравствуйте, piAnd, Вы писали:

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


A>А вообще я ошибочно поставил вопрос.

A>Каждый из экземпляров c2_x может быть создан в любой момент, поэтому один булевый флаг на всех и не катит. В том числе не катит и целочисленный, по причине ограниченности его диапазона. + C1 ничего не знает об C2. Поэтому как-то должен сам предоставлять некий метод или что-то еще...

А если флаг будет членом класса ?

class C1
{
public:
 C1()
    : foo_called_(false)
 {
 }

 void foo()
 {
  if(!foo_called_)
  {
   foo_called_ = true;
   // DO
  }
 }

private:
 bool foo_called_;
};

C1 c1; // c1.foo_called == false
c1.foo(); // c1.foo_called == true
C1 c2; // c2.foo_called == false
c2.foo(); // c2.foo_called == true
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 02.10.06 21:04
Оценка:
Здравствуйте, _nn_, Вы писали:
__>А если флаг будет членом класса ?
__>
__>class C1
__>{
__>public:
__> C1()
__>    : foo_called_(false)
__> {
__> }

__> void foo()
__> {
__>  if(!foo_called_)
__>  {
__>   foo_called_ = true;
__>   // DO
__>  }
__> }

__>private:
__> bool foo_called_;
__>};

__>C1 c1; // c1.foo_called == false
__>c1.foo(); // c1.foo_called == true
__>C1 c2; // c2.foo_called == false
__>c2.foo(); // c2.foo_called == true
__>


C1 c1;
C2<C1> c2_1; //c1.foo_called == false
c2_1.foo(); //c1.foo_called == true
C2<C1> c2_2; //c1.foo_called == true
c2_2.foo(); //невызовется, хотя с1.foo() не вызывалась с момента создания c2_2

PS: вобщем флаги в таком виде некатят. буду думать что менять в дизайне
Re: как отловить вызов ф-ции
От: Кодт Россия  
Дата: 03.10.06 09:32
Оценка: 6 (1)
Здравствуйте, piAnd, Вы писали:

Например, так
// счётчик времени
typedef void const* event_t;
int next_tick(event_t event) // event - произвольный идентификатор события. Подряд идущие события сливаются, чтобы уменьшить риск перемотки
{
    static event_t last_event = NULL;
    static int last_tick = 0;
    
    if(last_event != event) { last_event = event; ++last_tick; }
    return last_tick;
}


class C1
{
public:
    int tick;
    void foo() { tick=next_tick(this); ...... }
};

class C2
{
    C1* link;
    int tick;
    void foo()
    {
        int diff = this->tick - link->tick;
        if(diff < 0)
            ..... // были вызовы link->foo() после последнего this->foo()
        tick=next_tick(this);
        .....
    }
};


Можно и более изощрённую логику придумать. Скажем, очередь...
struct history_t
{
    typedef void const* event_t;
    std::vector<event_t> frame; // окно истории (последовательность событий в порядке их возникновения)
    
    void add(event_t event) // встаём в хвост очереди (естественно, выбывая из середины)
    {
        frame.erase(std::find(frame.begin(),frame.end(),event));
        frame.push_back(event);
    }
    int find(event_t event) const // положение в очереди (от хвоста); 0 означает отсутствие
    {
        return std::distance(std::find(frame.begin(),frame.end(),event),frame.end());
    }
} history;


class C1
{
    void foo() { history.add(this); ..... }
};

class C2
{
    C1* link;
    void foo()
    {
        int linkpos = history.find(link), thispos = history.find(this);
        // (0..thispos) - отрезок между настоящим моментом и последним вызовом this->foo()
        if(linkpos>0 && linkpos<thispos)
            ... // где-то между ними был совершён link->foo()
        if(thispos==0 && linkpos!=0)
            ... // this->foo() вызывается в первый раз, а link->foo() уже был
        if(linkpos==0)
            ... // link->foo() вообще не вызывался
        .......
        history.add(this);
    }
};

Если объектов много, то вместо вектора можно придумать что-нибудь побыстрее. Начиная от интрузивного списка, и кончая boost::multi_index.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: как отловить вызов ф-ции
От: Garrett Россия  
Дата: 03.10.06 10:17
Оценка: 6 (1)
Здравствуйте, piAnd, Вы писали:

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

//определение
class C1{
public:
   void foo()
   {
       for( i...)
          depends[i] = true;
       // DO
   }
   void create_dependency(ID){depends[ID] = false; }
   bool get_dependency(ID) {return depends[ID];// или false если в depends нет элемента ID}
private:
   map<ID,bool> depends;
};
//и
template <typename T>
class C2{
public:
   C2(T &Src):Ref(Src)
   {
      ID = ::GenerateC2ID();
      Ref.create_dependency(ID);
   }
   void foo()
   {
       if(Ref.get_dependency())
       {
          //DO
       }
   }
   T &Ref;
   ID;
};

//в главном cpp:
C1 c1;                 //depends пустой
c1.foo()
C2<C1> c2_1(с1);      // depends = {(1,false)}
c1.foo()              // depends = {(1,true)}
C2<C1> c2_2(с1);      // depends = {(1,true), (2,false) }
c1.foo()              // depends = {(1,true), (2,true) }
в борьбе со здравым смыслом победа будет за нами!
Re[2]: как отловить вызов ф-ции
От: Garrett Россия  
Дата: 03.10.06 10:19
Оценка:
Ну тут уже товарищ Кодт успел ответить, пока я пытался с условиями задачи разобраться и вообще от других дел отвязаться :user:
в борьбе со здравым смыслом победа будет за нами!
Re[3]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 03.10.06 15:12
Оценка:
Здравствуйте, Garrett, Вы писали:
G>Ну тут уже товарищ Кодт успел ответить, пока я пытался с условиями задачи разобраться и вообще от других дел отвязаться
всем спасибо за решения!
Re[2]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 03.10.06 15:28
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Например, так

К>
К>// счётчик времени
К>typedef void const* event_t;
К>int next_tick(event_t event) // event - произвольный идентификатор события. Подряд идущие события сливаются, чтобы уменьшить риск перемотки
К>{
К>    static event_t last_event = NULL;
К>    static int last_tick = 0;
    
К>    if(last_event != event) { last_event = event; ++last_tick; }
К>    return last_tick;
К>}
К>class C1
К>{
К>public:
К>    int tick;
К>    void foo() { tick=next_tick(this); ...... }
К>};

К>class C2
К>{
К>    C1* link;
К>    int tick;
К>    void foo()
К>    {
К>        int diff = this->tick - link->tick;
К>        if(diff < 0)
К>            ..... // были вызовы link->foo() после последнего this->foo()
К>        tick=next_tick(this);//кстати тут можно счетчик не накручивать,
К>                     //а просто поменять last_event => не выйдем
К>                     //за дозволеный диапазон int
К>        .....
К>    }
К>};
К>
Re[3]: как отловить вызов ф-ции
От: Кодт Россия  
Дата: 03.10.06 16:51
Оценка:
Здравствуйте, piAnd, Вы писали:

К>>class C2
К>>{
К>>    C1* link;
К>>    int tick;
К>>    void foo()
К>>    {
К>>        int diff = this->tick - link->tick;
К>>        if(diff < 0)
К>>            ..... // были вызовы link->foo() после последнего this->foo()
К>>        tick=next_tick(this);//кстати тут можно счетчик не накручивать,
К>>                     //а просто поменять last_event => не выйдем
К>>                     //за дозволеный диапазон int
К>>        .....
К>>    }
К>>};

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

Если целочисленное переполнение не приводит к аппаратным исключениям (а я надеюсь, что это так — иначе добрая половина сишных программ на этой архитектуре перестанет работать), то код устойчив к абсолютной перекрутке (переходу last_tick через INT_MAX).
Главное, чтобы между событиями someC1.foo() и someC2.foo() было не более INT_MAX разных событий. Именно поэтому сравнивается не this->tick с link->tick, а их разность с нулём.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: как отловить вызов ф-ции
От: piAnd Россия  
Дата: 04.10.06 10:02
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Если целочисленное переполнение не приводит к аппаратным исключениям (а я надеюсь, что это так — иначе добрая половина сишных программ на этой архитектуре перестанет работать), то код устойчив к абсолютной перекрутке (переходу last_tick через INT_MAX).

К>Главное, чтобы между событиями someC1.foo() и someC2.foo() было не более INT_MAX разных событий. Именно поэтому сравнивается не this->tick с link->tick, а их разность с нулём.
Подробно протестил варианты этой техники (где есть какой-либо перечислимый флаг, в данном случае tick). Вывод — каким бы ни был метод с использованием так или иначе инкрементального флага, будет существовать "краевой вариант обмана", т.е. будет существовать такой вариант манипуляций с вызовами, при котором одна из C2::foo будет обманута. Вобщем лучше тогда переделать сами классы, чем мутить доп. контейнеры...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.