Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Странности с шаблонами

354
03 июня 2008 года
ШпиЁн
468 / / 19.02.2006
Доброго всем времени суток.
есть шаблон:
Код:
template<class T> class global_ptr
{
public:
   
    global_ptr(T * val)
    {
        m_ptr = Collector::get_collector()->add_obj(val); // внутри val приводится к типу void*
        obj = val;
    }

    ~global_ptr()
    {
    }    
   
    inline T * operator ->() const
    {
          return obj;
             }

    operator T*()
    {
         return obj;
    }
   
private:
    Block * m_ptr;
    T * obj;
};

в тексте основной программы создаются экземпляр:
 
Код:
global_ptr<ThreadTester> tt = new ThreadTester();

в другом классе так:
 
Код:
global_ptr<Test> o1 = new Test(7, 8, 9);

ThreadTester и Test - маленькие классы, не суть важно что внутри.
НО. в программа вылетала при попытке пользоваться tt. при трассировке выяснилось что машинный код для global_ptr генерируется ДВА РАЗА, и РАЗНЫЙ
оптимизация отключена в обоих случаях.
нормальный рабочий вариант (debug)
(вызывается внутри класса)
Код:
global_ptr(T * val)
004208E0  push        ebp  
004208E1  mov         ebp,esp
004208E3  sub         esp,0CCh
004208E9  push        ebx  
004208EA  push        esi  
004208EB  push        edi  
004208EC  push        ecx  
004208ED  lea         edi,[ebp-0CCh]
004208F3  mov         ecx,33h
004208F8  mov         eax,0CCCCCCCCh
004208FD  rep stos    dword ptr [edi]
004208FF  pop         ecx  
00420900  mov         dword ptr [ebp-8],ecx
    {
        m_ptr = Collector::get_collector()->add_obj(val);
00420903  mov         eax,dword ptr [val]
00420906  push        eax  
00420907  call        Collector::get_collector (41CADCh)
0042090C  mov         ecx,eax
0042090E  call        Collector::add_obj (41D2C0h)
00420913  mov         ecx,dword ptr [this]
00420916  mov         dword ptr [ecx],eax
        obj = val;
00420918  mov         eax,dword ptr [this]
0042091B  mov         ecx,dword ptr [val]
0042091E  mov         dword ptr [eax+4],ecx
    }
00420921  mov         eax,dword ptr [this]
00420924  pop         edi  
00420925  pop         esi  
00420926  pop         ebx  
00420927  add         esp,0CCh
0042092D  cmp         ebp,esp
0042092F  call        @ILT+3760(__RTC_CheckEsp) (41CEB5h)
00420934  mov         esp,ebp
00420936  pop         ebp  
00420937  ret         4

Второй, странный вариант (debug):
(вызывается в функции main() - если это важно)
Код:
global_ptr(T * val)
004209D0  push        ebp  
004209D1  mov         ebp,esp
004209D3  sub         esp,0D0h
004209D9  push        ebx  
004209DA  push        esi  
004209DB  push        edi  
004209DC  push        ecx  
004209DD  lea         edi,[ebp-0D0h]
004209E3  mov         ecx,34h
004209E8  mov         eax,0CCCCCCCCh
004209ED  rep stos    dword ptr [edi]
004209EF  pop         ecx  
004209F0  mov         dword ptr [ebp-8],ecx
    {
        m_ptr = Collector::get_collector()->add_obj(val);
004209F3  cmp         dword ptr [val],0
004209F7  je          global_ptr<ThreadTester>::global_ptr<ThreadTester>+37h (420A07h)
004209F9  mov         eax,dword ptr [val]
004209FC  add         eax,18h
004209FF  mov         dword ptr [ebp-0D0h],eax
00420A05  jmp         global_ptr<ThreadTester>::global_ptr<ThreadTester>+41h (420A11h)
00420A07  mov         dword ptr [ebp-0D0h],0
00420A11  mov         ecx,dword ptr [ebp-0D0h]
00420A17  push        ecx  
00420A18  call        Collector::get_collector (41CADCh)
00420A1D  mov         ecx,eax
00420A1F  call        Collector::add_obj (41D2C0h)
00420A24  mov         edx,dword ptr [this]
00420A27  mov         dword ptr [edx],eax
        obj = val;
00420A29  mov         eax,dword ptr [this]
00420A2C  mov         ecx,dword ptr [val]
00420A2F  mov         dword ptr [eax+4],ecx
    }
00420A32  mov         eax,dword ptr [this]
00420A35  pop         edi  
00420A36  pop         esi  
00420A37  pop         ebx  
00420A38  add         esp,0D0h
00420A3E  cmp         ebp,esp
00420A40  call        @ILT+3760(__RTC_CheckEsp) (41CEB5h)
00420A45  mov         esp,ebp
00420A47  pop         ebp  
00420A48  ret         4

адреса, как видно - разные.
вопрос: что это такое, и почему это происходит? (и как избавиться от этого?)
заголовочный файл с реализацией global_ptr подключен один раз.
3
04 июня 2008 года
Green
4.8K / / 20.01.2000
Ты же дважды инстанируешь шаблон разными типами, поэтому и две реализации получаешь: одну - для ThreadTester, другую - для Test.

От этого не избавиться, т.к. в этом суть шаблонов - генерить реализации в зависимости от параметров шаблона.

Удивляет вот это: "// внутри val приводится к типу void*"
Зачем в C++ используешь void*?
Без него можно и нужно обходиться.
void* - причина многих ошибок.
354
04 июня 2008 года
ШпиЁн
468 / / 19.02.2006
add_obj сохраняет просто указатели на выделенную память - не суть важно что именно там, важно что есть.

насчет двух реализаций - понял, спасибо :)
но почему
Код:
m_ptr = Collector::get_collector()->add_obj(val);
004209F3  cmp         dword ptr [val],0
004209F7  je          global_ptr<ThreadTester>::global_ptr<ThreadTester>+37h (420A07h)
004209F9  mov         eax,dword ptr [val]
004209FC  add         eax,18h ;что это?
004209FF  mov         dword ptr [ebp-0D0h],eax
00420A05  jmp         global_ptr<ThreadTester>::global_ptr<ThreadTester>+41h (420A11h)
00420A07  mov         dword ptr [ebp-0D0h],0
00420A11  mov         ecx,dword ptr [ebp-0D0h]
00420A17  push        ecx  
00420A18  call        Collector::get_collector (41CADCh)
00420A1D  mov         ecx,eax
00420A1F  call        Collector::add_obj (41D2C0h)
00420A24  mov         edx,dword ptr [this]
00420A27  mov         dword ptr [edx],eax
        obj = val;

в итоге у меня в add_obj передается не адрес val, а на 18h больший. при попытке взять что-то по этому адресу - получается хлам (само собой). функции которые извлекают из недр добавленную add_obj память НЕ ОТНИМАЮТ 18h, и передают тот же хлам...
Я подогнал код, переделал все что можно - эта странность пропала, но
подскажите - ПОЧЕМУ компилятор генерирует такой код?
cmp dword ptr [val], 0 - это вообще как понимать, и зачем оно там?
3
04 июня 2008 года
Green
4.8K / / 20.01.2000
18h - это смещение в переданном объекте до данных представляющих класс ThreadTester.
Сдается мне, что у тебя в программе не совсем такая строчка:
 
Код:
global_ptr<ThreadTester> tt = new ThreadTester();

а скорее всего
 
Код:
global_ptr<ThreadTester> tt = new DerivedByThreadTester();

да еще и с множенственным наследованием.

А возможно add_obj принимает указатель на некоторый базовый класс, а не на ThreadTester.

Уточни, чем именно инициализируется tt.
И покажи определение класса ThreadTester и метода add_obj.

Твоя проблема IMHO как раз упирается именно в void*, т.к. описанные тобой ситуации возникают именно при потере информации о типе.
354
04 июня 2008 года
ШпиЁн
468 / / 19.02.2006
упс.
есть множественное наследование. ThreadTester от Object и Thread, а Test только от Object.
убрал наследование от Thread - странности пропали. :-D
прояснение сознания достигнуто. :)
спасибо.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог