чисто виртуальная функция
От: cthutq00  
Дата: 01.05.06 09:59
Оценка:
столкнулся с непонятной проблеммой и не пойму как ее решить.

1.есть библиотека в которой реализованы классы (библиотека моя)
в этой библиотеке есть класс с чисто виртуальным методом

если схематично — то примерно так


class Base {
    unsigned thread (void* arg);
    virtual void func(void) = 0;
}


при создании объекта класса создается поток (потоковая функция — thread);
в этом потоке происходит вызов чисто виртуальной функции


unsigned Base::thread (void* arg){
...
   func();
...
}


2. эта библиотека представляет собой один из проектов в solution (VC 8.0)
Второй проект на основе нее создает класс унаследованный от Base и переопределяет эту виртуальную
функию


class A : public Base{
    virtual void func(void) {
      ...
    }
}


так вот при отладке в Base::thread происходит вызов не A::func() а почему-то Base::func()
естественно при вызове чисто виртуальной функции все слетает

Почему это происходит я так и не могу понять. Складывается впечатление, что у А vptr указывает на vtbl Base.

Но почему компилятор неправильно собрал код ?
Самое интересное, что если вызвать func() из другого метода Base, то все срабатывает.

Как такое может быть ?
Re: чисто виртуальная функция
От: Константин Л. Россия  
Дата: 01.05.06 10:54
Оценка:
Здравствуйте, cthutq00, Вы писали:

[skipped]

А thread случайно не вызывается в конструкторе/деструкторе A/Base?
Estuve en Granada y me acorde' de ti
Re[2]: чисто виртуальная функция
От: cthutq00  
Дата: 01.05.06 11:19
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>А thread случайно не вызывается в конструкторе/деструкторе A/Base?


да я тоже грешил на это и думал, что объект еще не создан, но поток создается не в конструкторе, а
при вызове метода созданного объекта
Re[3]: чисто виртуальная функция
От: cthutq00  
Дата: 01.05.06 11:32
Оценка:
блин нащел косяк

написал тестовое приложение

main(){
A a;
_getch();
}


так вот компилятор гад слишком умный и создал код
так, что деструктор вызывается до _getch();

я пробовал и динамически создать объект — тоже.

и лишь когда зациклил код (тоесть без возможности выхода из main)
все заработало

Чертова оптимизация — пол дня угробил
Re[4]: чисто виртуальная функция
От: MuTPu4  
Дата: 01.05.06 15:30
Оценка:
Здравствуйте, cthutq00, Вы писали:

C>блин нащел косяк


C>написал тестовое приложение


C>
C>main(){
C>A a;
C>_getch();
C>}
C>


C>так вот компилятор гад слишком умный и создал код

C>так, что деструктор вызывается до _getch();

Это более чем странно, компилятор не имеет права делать такие вещи. Какой компилятор ты используешь? Приведи тестовый пример. Возможно, дело в какой-то неочевидной семантике функции _getch, попробуй переписать тест используя стандартные функции.
Re[5]: чисто виртуальная функция
От: cthutq00  
Дата: 01.05.06 16:17
Оценка:
Здравствуйте, MuTPu4, Вы писали:

MTP>Это более чем странно, компилятор не имеет права делать такие вещи. Какой компилятор ты используешь? Приведи тестовый пример. Возможно, дело в какой-то неочевидной семантике функции _getch, попробуй переписать тест используя стандартные функции.


компилятор VC 8.0

я вставил вместо _getch()

while (true){
   Sleep (100);
}


и все заработало
а до этого — деструктор вызывался до того, как произойдет переключение потока

Странно как-то ...
Re[6]: чисто виртуальная функция
От: MuTPu4  
Дата: 01.05.06 17:17
Оценка:
Здравствуйте, cthutq00, Вы писали:

C>компилятор VC 8.0


C>я вставил вместо _getch()


C>
C>while (true){
C>   Sleep (100);
C>}
C>


C>и все заработало

C>а до этого — деструктор вызывался до того, как произойдет переключение потока

C>Странно как-то ...


С многопоточностью я тебе врядли помогу, но могу сказать, что, скорее всего, дело совсем не в ошибке кодогенератора, а в некорректной работе в многопоточной среде с твоей стороны.
Re[7]: чисто виртуальная функция
От: cthutq00  
Дата: 01.05.06 17:44
Оценка:
Здравствуйте, MuTPu4, Вы писали:

MTP>С многопоточностью я тебе врядли помогу, но могу сказать, что, скорее всего, дело совсем не в ошибке кодогенератора, а в некорректной работе в многопоточной среде с твоей стороны.


у меня при вызове метода создается поток
а при вызове деструктора ожидается его завершение. И пока он не завершиться — объект не умрет

неужели до выхода из деструктора таблиза виртуальных функций уже разрушена ?

Вроде не должно такого быть
Re[8]: чисто виртуальная функция
От: WolfHound  
Дата: 01.05.06 20:41
Оценка:
Здравствуйте, cthutq00, Вы писали:

C>неужели до выхода из деструктора таблиза виртуальных функций уже разрушена ?

C>Вроде не должно такого быть
А ждешь случайно не в деструкторе Base?
Если да то A уже разрушен и таблица виртуальных функций указывает на функции Base...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: чисто виртуальная функция
От: Bell Россия  
Дата: 02.05.06 07:33
Оценка:
Здравствуйте, cthutq00, Вы писали:

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


MTP>>С многопоточностью я тебе врядли помогу, но могу сказать, что, скорее всего, дело совсем не в ошибке кодогенератора, а в некорректной работе в многопоточной среде с твоей стороны.


C>у меня при вызове метода создается поток

C>а при вызове деструктора ожидается его завершение. И пока он не завершиться — объект не умрет

C>неужели до выхода из деструктора таблиза виртуальных функций уже разрушена ?

В момент вызова деструктора vptr указывает на таблицу того класса, деструктор которого работает в данный момент.
Так что если ты недеешься в деструкторе Base дернуть виртуальную функцию из A — то из этого ничего не выйдет. Эта тема поднималась неоднократно, и при желании все подробности можно найти в поиске.

Еще одна догадка:
Если твой код выглядит примерно так:
{
   A a;
   a.create_thread();//функция потока должна захватить какой-то объект синхронизации
}//деструктор A ждет на этот самом объекте синхронизации

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

ЗЫ
Минимальный пример существенно бы ускорил процесс поиска ошибки.
Любите книгу — источник знаний (с) М.Горький
Re[9]: чисто виртуальная функция
От: cthutq00  
Дата: 02.05.06 15:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>А ждешь случайно не в деструкторе Base?

WH>Если да то A уже разрушен и таблица виртуальных функций указывает на функции Base...

блин — точно. Жду в Base. А как можно заставить ждать в порожденном классе?
просто он ничего не должен знать про поток, а просто переопределить
виртуальную функцию и что-то сделать.
Re[10]: чисто виртуальная функция
От: rg45 СССР  
Дата: 02.05.06 16:11
Оценка:
"cthutq00" <53488@users.rsdn.ru> wrote in message news:1876879@news.rsdn.ru...
> Здравствуйте, WolfHound, Вы писали:
>
> WH>А ждешь случайно не в деструкторе Base?
> WH>Если да то A уже разрушен и таблица виртуальных функций указывает на функции Base...
>
> блин — точно. Жду в Base. А как можно заставить ждать в порожденном классе?
> просто он ничего не должен знать про поток, а просто переопределить
> виртуальную функцию и что-то сделать.

Ждать нужно не в конструкторе, а в специальной функции базового класса, из нее вызов виртуального метода пойдет без проблем
Posted via RSDN NNTP Server 2.0
Я жду, когда этот пидарас
Автор: Bj777x
Дата: 22.06.20
либо удалит свое хамство здесь
Автор: Bj777x
Дата: 14.10 21:26
и здесь
Автор: Bj777x
Дата: 27.09 11:34
, либо восстановит ответы.
Re[11]: чисто виртуальная функция
От: cthutq00  
Дата: 02.05.06 16:26
Оценка:
Здравствуйте, rg45, Вы писали:


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


что-то не вкурил
Re[10]: чисто виртуальная функция
От: Константин Л. Россия  
Дата: 02.05.06 16:59
Оценка:
Здравствуйте, cthutq00, Вы писали:

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


WH>>А ждешь случайно не в деструкторе Base?

WH>>Если да то A уже разрушен и таблица виртуальных функций указывает на функции Base...

C>блин — точно. Жду в Base. А как можно заставить ждать в порожденном классе?

C>просто он ничего не должен знать про поток, а просто переопределить
C>виртуальную функцию и что-то сделать.

Я ж спрашивал, из конструктора/деструктора зовешь?
Estuve en Granada y me acorde' de ti
Re[12]: чисто виртуальная функция
От: rg45 СССР  
Дата: 02.05.06 17:08
Оценка: 4 (1)
"cthutq00" <53488@users.rsdn.ru> wrote in message news:1876926@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
>
> R>Ждать нужно не в конструкторе, а в специальной функции базового класса, из нее вызов виртуального метода пойдет без проблем
>
> что-то не вкурил

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

class ThreadHandler
{
public:
  virtual ~ThreadHandler() = 0;

  bool is_active() const = 0;

  virtual void start() = 0;
  virtual void terminate() = 0;
  virtual void suspend() = 0;
  virtual void resume() = 0;
};

class ThreadFacade
{
public:
   Thread(boost::shared_ptr<ThreadHandler>) 
   : m_thread_handler(thread_handler)
   {
      m_thread_handler->start();
   }

   virtual ~ThreadFacade()
   {
#ifdef MY_FORCE_TERMINATE_THREAD
      m_thread_handler->terminate();  
#else
      while(m_thread_handler->is_active())
          Sleep(2);
#endif   
   }

  bool is_active() const                 {return m_thread_handler->is_active();}
  void suspend();                 {m_thread_handler->suspend();}  
  void resume();                   {m_thread_handler->resume();} 

private:
  boost::shared_ptr<ThreadHandler> m_thread_handler;
};
Posted via RSDN NNTP Server 2.0
Я жду, когда этот пидарас
Автор: Bj777x
Дата: 22.06.20
либо удалит свое хамство здесь
Автор: Bj777x
Дата: 14.10 21:26
и здесь
Автор: Bj777x
Дата: 27.09 11:34
, либо восстановит ответы.
Re[13]: чисто виртуальная функция
От: Константин Л. Россия  
Дата: 02.05.06 17:21
Оценка:
Здравствуйте, rg45, Вы писали:

А не сделать ли ему так?


class Base
{
public:

  virtual void func() =0;

  virtual ~Base(){}

};

template <typename T>
class BaseImpl : public Base
{
public:

   virtual void func()
   {
      T::func_();
   }

   ~BaseImpl()
   {
      T::func_();
   }
}

class A : public BaseImpl<A>
{
private:/*public*/

   void func_()
   {
      std::cout<<"la-la-la";
   }
};


1) остается интерфейсный вид
2) избавляемся от косвенного вызова pvf
Estuve en Granada y me acorde' de ti
Re[14]: чисто виртуальная функция
От: Константин Л. Россия  
Дата: 02.05.06 17:27
Оценка:
Здравствуйте, Константин Л., Вы писали:

Забыл сказать, что тем самым обязываем всех наследников определять func_, что есть хорошо
Estuve en Granada y me acorde' de ti
Re[14]: чисто виртуальная функция
От: rg45 СССР  
Дата: 02.05.06 17:37
Оценка: 1 (1)
" Константин Л. " <44487@users.rsdn.ru> wrote in message news:1876978@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
> А не сделать ли ему так?
>
>
> 
> class Base
> {
> public:
> 
>  virtual void func() =0;
> 
>  virtual ~Base(){}
> 
> };
> 
> template <typename T>
> class BaseImpl : public Base
> {
> public:
> 
>   virtual void func()
>   {
>      T::func_();
>   }
> 
>   ~BaseImpl()
>   {
>      T::func_();
>   }
> }
> 
> class A : public BaseImpl<A>
> {
> private:/*public*/
> 
>   void func_()
>   {
>      std::cout<<"la-la-la";
>   }
> };
> 
>

>
> 1) остается интерфейсный вид
> 2) избавляемся от косвенного вызова pvf

Тоже вариант, конечно, но не совсем надежно: кому-нибудь стукнет в голову унаследоваться от A и в наследнике дать свою реализацию func_ и вся идея наворачивается.
Posted via RSDN NNTP Server 2.0
Я жду, когда этот пидарас
Автор: Bj777x
Дата: 22.06.20
либо удалит свое хамство здесь
Автор: Bj777x
Дата: 14.10 21:26
и здесь
Автор: Bj777x
Дата: 27.09 11:34
, либо восстановит ответы.
Re[15]: чисто виртуальная функция
От: Константин Л. Россия  
Дата: 02.05.06 17:51
Оценка:
Здравствуйте, rg45, Вы писали:

>>
>> class A : public BaseImpl<A>
>> {
>> private:/*public*/
>> 
>>   void func_()
>>   {
>>      std::cout<<"la-la-la";
>>   }
>> };
>> 
>>

>>
>> 1) остается интерфейсный вид
>> 2) избавляемся от косвенного вызова pvf

R>Тоже вариант, конечно, но не совсем надежно: кому-нибудь стукнет в голову унаследоваться от A и в наследнике дать свою реализацию func_ и вся идея наворачивается.


Нечего от A наследоваться

А такое извращение?

template <class Impl>
class A : public BaseImpl<Impl>
{
private:/*public*/
 
   void func_()
   {
      Impl::func_();
   }
 };

class B : public A<B>
{
  void func_()
  { /**/ }
};


Estuve en Granada y me acorde' de ti
Re[16]: чисто виртуальная функция
От: rg45 СССР  
Дата: 02.05.06 17:56
Оценка: :)
" Константин Л. " <44487@users.rsdn.ru> wrote in message news:1877004@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
>>>
>>> class A : public BaseImpl<A>
>>> {
>>> private:/*public*/
>>> 
>>>   void func_()
>>>   {
>>>      std::cout<<"la-la-la";
>>>   }
>>> };
>>> 
>>>

>>>
>>> 1) остается интерфейсный вид
>>> 2) избавляемся от косвенного вызова pvf
>
> R>Тоже вариант, конечно, но не совсем надежно: кому-нибудь стукнет в голову унаследоваться от A и в наследнике дать свою реализацию func_ и вся идея наворачивается.
>
> Нечего от A наследоваться
>
> А такое извращение?
>
>
> template <class Impl>
> class A : public BaseImpl<Impl>
> {
> private:/*public*/
> 
>   void func_()
>   {
>      Impl::func_();
>   }
> };
> 
> class B : public A<B>
> {
>  void func_()
>  { /**/ }
> };
> 
>

>
>

Ну а теперь нечего наследоваться от B
Posted via RSDN NNTP Server 2.0
Я жду, когда этот пидарас
Автор: Bj777x
Дата: 22.06.20
либо удалит свое хамство здесь
Автор: Bj777x
Дата: 14.10 21:26
и здесь
Автор: Bj777x
Дата: 27.09 11:34
, либо восстановит ответы.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.