
В экосистеме современного C++ прочно укоренилось мнение: классический динамический полиморфизм через виртуальные функции (vtable) — это устаревший, медленный и недружелюбный к кэшу процессора механизм. В качестве «серебряной пули» модно предлагать связку std::variant и std::visit. По интернету кочуют статьи, утверждающие, что std::visit выполняет диспетчеризацию за фиксированное время O(1) и полностью уничтожает старый добрый ООП-подход.
Но в таких сравнениях авторы часто совершают методологическую ошибку: они противопоставляют вектор указателей std::vector<Base*> вектору сырых объектов std::vector<std::variant>. Разумеется, std::variant побеждает, но не из-за механики вызова, а благодаря стопроцентной локальности данных в кэше процессора.
Давайте снимем розовые очки, уравняем условия и изолируем саму механику вызовов. Представьте реальный сценарий: объекты тяжелые, создаются динамически в разное время и разбросаны по куче (Heap), а мы оперируем массивами их адресов.
Мы столкнем лоб в лоб std::vector<Base*> и std::vector<std::variant<TypeA, TypeB, TypeC>*> в условиях раздельной компиляции (когда оптимизатор -O2 не видит тела функций и не может применить тотальный инлайнинг).