CXX95 Telegram 94
#madskillz

Напиши свой собственный RTTI 🖱

RTTI (run-time type information) это некая информация о всех виртуальных классах, которая попадает в бинарник программы.
Благодаря этому работают dynamic_cast<> (приведение типа в run-time) и typeid.
Генерацию RTTI можно выключить флагом компиляции -fno-rtti.

Пусть у нас есть указатель X* x (или ссылка X& x). Указатель может указывать на объект с типом не X (но это обязательно будет тип-потомок X).

Есть три варианта приведений типа X к типу Y (тип Y тоже не обязательно реальный тип объекта):

1️⃣Upcast: Y - класс-предок X.
Для этого не требуется никакого RTTI. Такое приведение всегда возможно. Можно было бы обойтись static_cast<> (приведение типа в compile-time).

2️⃣ Downcast: Y - класс-потомок X.
В этом случае обычно используют dynamic_cast<>. Если окажется, что тип объекта не Y (или не какого-то потомка Y), то приведения не случится.

Интересно, что если программист совершенно уверен, что приведение возможно, то можно использовать static_cast<> и не делать run-time проверку. Если окажется, что он был не прав, то получится undefined behaviour 😁

3️⃣ Sidecast: X и Y никак не связаны между собой.
Такое возможно, если X* указывает на объект класса Z:
class Z : public X, public Y {...};
Такие касты dynamic_cast<> тоже умеет делать.
Скорее всего sidecast значит, что в программе есть серьезные ошибки дизайна 🧐

Некоторые проекты не используют "официальный" RTTI 😡
Почему так происходит, на примере очень популярных проектов:

1️⃣ Protobuf: вынужденная поддержка проектов с -fno-rtti.

В protobuf есть базовый для всех "месседжей" класс google::protobuf::Message.

Чтобы попробовать сделать downcast от базового класса до класса "месседжа", можно использовать функцию DynamicCastToGenerated.
Как видно по исходнику, если уж нельзя вызвать dynamic_cast<>, то используется костыль - суррогат RTTI: сравнение ссылки на "рефлексию" (уникальное описание "месседжа"). Эту ссылку возвращает виртуальный метод.

Какие ограничения этого подхода: С -fno-rtti доступен только downcast строго на указанный класс - потомок класса Message.

2️⃣ LLVM: своя реализация RTTI для быстродействия.

Clang и LLVM имеют большую иерархию типов и делают огромную кучу проверок на типы. Большая часть кода в компиляторах (оптимизации, кодогенерация, ...) завязана на поиск специфических паттернов и операциях на них. Для этого необходимо проверять тип объектов в овер9000 местах, поэтому быстродействие dynamic_cast становится узким местом.

А быстродействие у dynamic_cast сравнительно плохое. Он должен делать обход иерархии наследования и вычисляет путь обхода динамическим образом. Это на несколько порядков медленнее, чем просто вызвать виртуальный метод и что-то сравнить.

В документации есть крутая статья, как сделать свой RTTI "почти как в LLVM" - How to set up LLVM-style RTTI for your class hierarchy. Для этого заводится специальный enum, и каждый класс реализует статический метод classof. Вместо обхода иерархии наследования делается один вызов виртуального метода!

Какие ограничения этого подхода: Дополнительный код - enum, статический метод в каждом классе. Нужно следить за тем, чтобы соответствие между enum и классами не разломалось (хотя тут могут помочь кодогенераторы). Эта схема работает, только если иерархия классов известна заранее (стандартный C++ RTTI такого не требует).

Всего известно три главных аргумента "против RTTI":
🅱️ Занимает память в бинарнике - очень сомнительный аргумент. RTTI не требует столько памяти, чтобы это стало заметно, по крайней мере в 2023 году.
🅱️ Медленно работает - хороший аргумент, если dynamic_cast<> является узким местом в программе. Но это должна быть специфическая программа, как поиск паттернов в структурах с большой иерархией классов... (например, компилятор C++)
🅱️ Его использование - ошибка дизайна - неожиданный аргумент, но именно по этой причине RTTI запрещен в Google C++ Style Guide. По ссылке есть описание "почему это плохо". Конечно, из каждого правила есть исключение.
Please open Telegram to view this post
VIEW IN TELEGRAM



tgoop.com/cxx95/94
Create:
Last Update:

#madskillz

Напиши свой собственный RTTI 🖱

RTTI (run-time type information) это некая информация о всех виртуальных классах, которая попадает в бинарник программы.
Благодаря этому работают dynamic_cast<> (приведение типа в run-time) и typeid.
Генерацию RTTI можно выключить флагом компиляции -fno-rtti.

Пусть у нас есть указатель X* x (или ссылка X& x). Указатель может указывать на объект с типом не X (но это обязательно будет тип-потомок X).

Есть три варианта приведений типа X к типу Y (тип Y тоже не обязательно реальный тип объекта):

1️⃣Upcast: Y - класс-предок X.
Для этого не требуется никакого RTTI. Такое приведение всегда возможно. Можно было бы обойтись static_cast<> (приведение типа в compile-time).

2️⃣ Downcast: Y - класс-потомок X.
В этом случае обычно используют dynamic_cast<>. Если окажется, что тип объекта не Y (или не какого-то потомка Y), то приведения не случится.

Интересно, что если программист совершенно уверен, что приведение возможно, то можно использовать static_cast<> и не делать run-time проверку. Если окажется, что он был не прав, то получится undefined behaviour 😁

3️⃣ Sidecast: X и Y никак не связаны между собой.
Такое возможно, если X* указывает на объект класса Z:

class Z : public X, public Y {...};
Такие касты dynamic_cast<> тоже умеет делать.
Скорее всего sidecast значит, что в программе есть серьезные ошибки дизайна 🧐

Некоторые проекты не используют "официальный" RTTI 😡
Почему так происходит, на примере очень популярных проектов:

1️⃣ Protobuf: вынужденная поддержка проектов с -fno-rtti.

В protobuf есть базовый для всех "месседжей" класс google::protobuf::Message.

Чтобы попробовать сделать downcast от базового класса до класса "месседжа", можно использовать функцию DynamicCastToGenerated.
Как видно по исходнику, если уж нельзя вызвать dynamic_cast<>, то используется костыль - суррогат RTTI: сравнение ссылки на "рефлексию" (уникальное описание "месседжа"). Эту ссылку возвращает виртуальный метод.

Какие ограничения этого подхода: С -fno-rtti доступен только downcast строго на указанный класс - потомок класса Message.

2️⃣ LLVM: своя реализация RTTI для быстродействия.

Clang и LLVM имеют большую иерархию типов и делают огромную кучу проверок на типы. Большая часть кода в компиляторах (оптимизации, кодогенерация, ...) завязана на поиск специфических паттернов и операциях на них. Для этого необходимо проверять тип объектов в овер9000 местах, поэтому быстродействие dynamic_cast становится узким местом.

А быстродействие у dynamic_cast сравнительно плохое. Он должен делать обход иерархии наследования и вычисляет путь обхода динамическим образом. Это на несколько порядков медленнее, чем просто вызвать виртуальный метод и что-то сравнить.

В документации есть крутая статья, как сделать свой RTTI "почти как в LLVM" - How to set up LLVM-style RTTI for your class hierarchy. Для этого заводится специальный enum, и каждый класс реализует статический метод classof. Вместо обхода иерархии наследования делается один вызов виртуального метода!

Какие ограничения этого подхода: Дополнительный код - enum, статический метод в каждом классе. Нужно следить за тем, чтобы соответствие между enum и классами не разломалось (хотя тут могут помочь кодогенераторы). Эта схема работает, только если иерархия классов известна заранее (стандартный C++ RTTI такого не требует).

Всего известно три главных аргумента "против RTTI":
🅱️ Занимает память в бинарнике - очень сомнительный аргумент. RTTI не требует столько памяти, чтобы это стало заметно, по крайней мере в 2023 году.
🅱️ Медленно работает - хороший аргумент, если dynamic_cast<> является узким местом в программе. Но это должна быть специфическая программа, как поиск паттернов в структурах с большой иерархией классов... (например, компилятор C++)
🅱️ Его использование - ошибка дизайна - неожиданный аргумент, но именно по этой причине RTTI запрещен в Google C++ Style Guide. По ссылке есть описание "почему это плохо". Конечно, из каждого правила есть исключение.

BY C++95


Share with your friend now:
tgoop.com/cxx95/94

View MORE
Open in Telegram


Telegram News

Date: |

2How to set up a Telegram channel? (A step-by-step tutorial) In 2018, Telegram’s audience reached 200 million people, with 500,000 new users joining the messenger every day. It was launched for iOS on 14 August 2013 and Android on 20 October 2013. 5Telegram Channel avatar size/dimensions 3How to create a Telegram channel? To delete a channel with over 1,000 subscribers, you need to contact user support
from us


Telegram C++95
FROM American