Является ли LLVM исключением из правила для избежания динамического приведения?
-
05-07-2019 - |
Вопрос
LLVM имеет собственную альтернативу RTTI, созданную вручную, которая является улучшением скорости по сравнению со встроенным RTTI и позволяет выполнять динамическое приведение к классам без vtable (dyn_cast
). Однако его все равно можно использовать точно так же, как dynamic_cast<>
, хотя он позволяет использовать его с большим количеством классов.
dyn_cast<>
документация шаблона
LLVM - это авторитетный проект C ++, так что, похоже, это противоречит распространенному утверждению, что слишком много динамических приведений является признаком плохого дизайна, также известного как запах кода. Несомненно, более динамичное приведение типов не улучшает его использование в дизайне по сравнению со стандартным dynamic_cast
. Так кто здесь? Существуют ли случаи, когда широкомасштабное использование динамического приведения является хорошим выбором при разработке кода C ++? Google обнаруживает 690 случаев такого рода динамического приведения в исходном коде магистрали LLVM.
Решение
Хотя снижение производительности - это причина, по которой следует избегать dynamic_cast<>
для больших иерархий классов, это не единственная причина, по которой вы можете их избежать. Из-за этого требования лучше не поощрять использование dyn_cast<>
из-за этой заявки.
С другой стороны, нет ничего плохого в использовании goto
, когда это лучший инструмент для работы. Если его использование оправдано и является самым чистым способом решения проблемы, то это всегда правильно, независимо от & Quot; общего высказывания & Quot;.
Я бы, конечно, не стал избегать популярных проектов просто потому, что они используют <=> s, <=> s или любую другую идиому, которая потеряла популярность.
Другие советы
Я думаю, что динамические броски плохие не потому, что они медленные, а потому, что они подразумевают, что ваш код слишком тесно связан.
Я только очень быстро взглянул на реализацию dyn_cast и isa в документации LLVM.
Пример в коде имеет следующее:
struct bar {
bar() {}
private:
bar(const bar &);
};
struct foo {
void ext() const;
/* static bool classof(const bar *X) {
cerr << "Classof: " << X << "\n";
return true;
}*/
};
template <> inline bool isa_impl<foo,bar>(const bar &Val) {
errs() << "Classof: " << &Val << "\n";
return true;
}
Тест вызывается с помощью B
и имеет:
if (!isa<foo>(B1)) return;
if (!isa<foo>(B2)) return;
Если я правильно понимаю, что происходит, шаблон isa
(который используется dyn_cast
) использует явную специализацию isa_impl
, чтобы связать панель с foo. В приведенных примерах кажется, что isa<foo>(B1)
возвращает true!
В любом случае, это поведение сильно отличается от поведения dynamic_cast, поэтому я действительно не думаю, что вы можете сравнить их друг с другом.
Очевидно, что я неправильно понимаю, что делает LLVM, поэтому, пожалуйста, дайте мне знать, если я не понял код!