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
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
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 подключен один раз.
От этого не избавиться, т.к. в этом суть шаблонов - генерить реализации в зависимости от параметров шаблона.
Удивляет вот это: "// внутри val приводится к типу void*"
Зачем в C++ используешь void*?
Без него можно и нужно обходиться.
void* - причина многих ошибок.
насчет двух реализаций - понял, спасибо :)
но почему
Код:
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;
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 - это вообще как понимать, и зачем оно там?
Сдается мне, что у тебя в программе не совсем такая строчка:
Код:
global_ptr<ThreadTester> tt = new ThreadTester();
а скорее всего
Код:
global_ptr<ThreadTester> tt = new DerivedByThreadTester();
да еще и с множенственным наследованием.
А возможно add_obj принимает указатель на некоторый базовый класс, а не на ThreadTester.
Уточни, чем именно инициализируется tt.
И покажи определение класса ThreadTester и метода add_obj.
Твоя проблема IMHO как раз упирается именно в void*, т.к. описанные тобой ситуации возникают именно при потере информации о типе.
есть множественное наследование. ThreadTester от Object и Thread, а Test только от Object.
убрал наследование от Thread - странности пропали. :-D
прояснение сознания достигнуто. :)
спасибо.