Вот краткий тест вашего примера (с реализацией MyA::foo()
, которая просто возвращает 42
).Все эти тесты были с 32-битными целями - возможно, что с 64-битными целями могут быть разные результатыТакже стоит отметить, что использование опции -flto
(GCC) или опции /GL
(MSVC) приводит к полной оптимизации - везде, где вызывается MyB::foo()
, его просто заменяют на 42
.
сGCC (MinGW 4.5.1):
gcc -g -O3 -o test.exe myb.cpp mya.cpp test.cpp
вызов MyB :: foo () не был оптимизирован.MyB::foo()
сам был слегка оптимизирован для:
Dump of assembler code for function MyB::foo() const:
0x00401350 <+0>: push %ebp
0x00401351 <+1>: mov %esp,%ebp
0x00401353 <+3>: sub $0x8,%esp
=> 0x00401356 <+6>: leave
0x00401357 <+7>: jmp 0x401360 <MyA::foo() const>
То есть, вводная часть ввода остается на месте, но немедленно отменяется (инструкция leave
), и код переходит к MyA :: foo () дляделать реальную работу.Однако это оптимизация, которую выполняет компилятор (не компоновщик), поскольку он понимает, что MyB::foo()
просто возвращает то, что возвращает MyA::foo()
.Я не уверен, почему пролог остался в.
MSVC 16 (из VS 2010) обрабатывал вещи немного по-другому:
MyB::foo()
закончился как два прыжка - один к одномуthunk 'некоторого вида:
0:000> u myb!MyB::foo
myb!MyB::foo:
001a1030 e9d0ffffff jmp myb!ILT+0(?fooMyAQBEHXZ) (001a1005)
И thunk просто перепрыгнул на MyA::foo()
:
myb!ILT+0(?fooMyAQBEHXZ):
001a1005 e936000000 jmp myb!MyA::foo (001a1040)
Опять же - это было в значительной степени (полностью?) выполнено компилятором, так как еслиесли вы посмотрите на объектный код, созданный до компоновки, MyB::foo()
скомпилирован с простым переходом к MyA::foo()
.
Итак, если все это свести к минимуму - похоже, без явного вызова LTO / LTCG, компоновщики сегодняне желает / не может выполнить оптимизацию удаления вызова для MyB::foo()
в целом, даже если MyB::foo()
- это простой переход к MyA::foo()
.
Так что, если вы хотите оптимизировать время ссылки, используйте *Опции 1042 * (для GCC) или /GL
(для компилятора MSVC) и /LTCG
(для компоновщика MSVC).