В качестве альтернативы BaseThing может иметь чистый виртуальный GetID()
, который будет использоваться для вывода типа вместо использования typeid. В этой ситуации только с 1 уровнем наследования, какова стоимость typeid по сравнению со стоимостью вызова виртуальной функции? Я знаю, что typeid каким-то образом использует vtable, но как именно это работает?
В Linux и Mac или где-либо еще, использующем Itanium C++ ABI, typeid(x)
компилируется в две инструкции загрузки — он просто загружает vptr (то есть адрес некоторой vtable) из первых 8 байтов объекта x
, а затем загружает -1
th указатель из этой vtable. Этот указатель &typeid(x)
. Это на одну функцию менее затратно, чем вызов виртуального метода.
В Windows это включает порядка четырех инструкций загрузки и пару (незначительных) операций ALU, потому что Microsoft C++ ABI немного более предприимчивым. (источник). Честно говоря, это может оказаться наравне с вызовом виртуального метода. Но это все еще слишком дешево по сравнению с dynamic_cast
.
dynamic_cast
включает вызов функции в среду выполнения C++, которая имеет множество загрузок, условных переходов и тому подобного.
Так что да, использование typeid
будет намного быстрее, чем dynamic_cast
. Будет ли это правильно для вашего варианта использования? — это сомнительно. (См. другие ответы о заменяемости Лисков и т. д.) Но будет ли это быстро? — да.
Здесь я взял код игрушечного теста из высоко оцененного ответа Вона и превратил его в настоящий тест, избегая очевидных оптимизация подъема цикла, которая испортила все его тайминги. Результат для libc++abi на моем Macbook:
$ g++ test.cc -lbenchmark -std=c++14; ./a.out
Run on (4 X 2400 MHz CPU s)
2017-06-27 20:44:12
Benchmark Time CPU Iterations
---------------------------------------------------------
bench_dynamic_cast 70407 ns 70355 ns 9712
bench_typeid 31205 ns 31185 ns 21877
bench_id_method 30453 ns 29956 ns 25039
$ g++ test.cc -lbenchmark -std=c++14 -O3; ./a.out
Run on (4 X 2400 MHz CPU s)
2017-06-27 20:44:27
Benchmark Time CPU Iterations
---------------------------------------------------------
bench_dynamic_cast 57613 ns 57591 ns 11441
bench_typeid 12930 ns 12844 ns 56370
bench_id_method 20942 ns 20585 ns 33965
(Нижний ns
лучше. Вы можете игнорировать последние два столбца: «ЦП» просто показывает, что он тратит все свое время на работу и не ждет, а «Итерации» — это просто количество запусков, которое потребовалось, чтобы получить хорошую погрешность. .)
Вы можете видеть, что typeid
проигрывает dynamic_cast
даже при -O0
, но когда вы включаете оптимизацию, становится еще лучше, потому что компилятор может оптимизировать любой код, который вы пишете. Весь этот уродливый код спрятан внутри __dynamic_cast
libc++abi функция не может быть оптимизирована компилятором больше, чем это уже было, поэтому включение -O3
не сильно помогло.
person
Quuxplusone
schedule
28.06.2017
typeid
(в сочетании сstatic_cast
) в порядке. Однако пользовательский код использует функциюget
и не беспокоится о typeid. - На самом деле, вы можете использовать его вместо того, чтобы накатывать свой собственный, поскольку он делает больше для вас (клонирование и управление динамической памятью). - person visitor   schedule 11.11.2011