Является ли в C++ "открытый тип int без знака" в базовом классе более быстрой альтернативой dynamic_cast?

В C++ медленная "dynamic_cast" является известным фактом. Я подумал о следующем простом способе узнать тип объекта в иерархии. Может кто-нибудь объяснить, может ли это быть медленнее, чем dynamic_cast? А если нет, то почему это не является обычной практикой, учитывая, что скорость является худшим недостатком C++ по сравнению с C?

struct Base {
  unsigned m_type;
  Base(unsigned type): m_type(type) {}
  Base(): m_type(0) {}
};
struct Derived1: Base {
  Derived1(): Base(1) {}
  Derived1(int type): Base(type) {}
};
struct Derived2: Base {
  Derived2(): Base(2) {}
};
struct Derived3: Derived1 {
  Derived3(): Derived1(3) {}
};
void my_func(Base * p) {
  if (p - > m_type == 0) {} 
  else if (p - > m_type == 1) {} 
  else if (p - > m_type == 2) {} 
  else if (p - > m_type == 3) {}
}

2 ответа

Может кто-нибудь объяснить, может ли это быть медленнее, чем dynamic_cast?

Это может быть медленнее, чем dynamic_cast'ing, когда...

  • компилятор может выяснить, из чего вы используете dynamic_cast, и, таким образом, избежать каких-либо действий для динамического приведения.
  • Base-приобретенные объекты являются неизменяемыми, что позволяет выполнять все виды оптимизации, в то время как ваши классы содержат переменную изменяемого типа.
  • у вас большая и сложная иерархия типов, поэтому у вас есть много сравнений.

Кроме того, вы действительно проверили, насколько медленный динамический_каст относительно других вещей, которые вы могли бы делать?

Почему это не распространенная практика [?]

  1. Поскольку это делает код более сложным, добавляет непреднамеренную потенциальную семантику и возможности и идет вразрез с основными механизмами абстракции языка.
  2. Потому что это требует, чтобы базовый класс знал обо всех своих производных классах (или иначе вы по сути переопределяете динамическое приведение).
  3. Потому что это делает некоторые части специфичного для класса кода локальными для определения класса, а другие части специфичного для класса кода - локальными для базового класса.

... учитывая, что скорость является худшим недостатком C++ по сравнению с C?

Это не так. В наши дни вполне возможно (и часто) писать более эффективный код на C++, чем семантический эквивалент на C.

Но в любом случае это не должно иметь значения, поскольку у вас нет бизнеса, выполняющего динамическое приведение кода, критичного к производительности; это недостаток дизайна, как предлагает @NathanOliver в комментарии.

В C++ медленная "dynamic_cast" является известным фактом.

Это был известный факт тридцать лет назад (когда я впервые начал использовать компиляторы C++) 1989/1990 (тогда я использовал любой компилятор, установленный по умолчанию на рабочих станциях Sun). НО это больше не относится к современным компиляторам.

Я не забываю загружать g++ (я думаю, 2.4; ок. 1996-1998), чтобы посмотреть, что происходит (см. Ниже). Компилятор (g++) будет проходить по иерархии классов и на каждом уровне будет выполнять сравнение строк с именами классов при поиске правильной записи типа. Это было сделано, поскольку каждый модуль компиляции потенциально имел свой собственный уникальный набор записей типа (так что вы не могли просто сравнивать указатели).

А если нет, то почему это не обычная практика?

В результате многие люди действительно написали свои собственные версии динамического приведения для повышения скорости (но опять же люди все еще пытались понять, как написать хороший C++ в те дни, и большая часть кода была написана как C, так что производительность, вероятно, не была ошибка в динамической трансляции). Но пара реализаций, которые я видел, была чрезвычайно хрупкой и содержала множество ошибок. Вот почему я посмотрел, как работает g ++. К этому времени (1998) самописный динамический состав, который использовала моя компания, показывал свой возраст, и я разорвал его, чтобы использовать версию компилятора (никаких измеримых изменений производительности, но множество таинственных ошибок исчезло).

К счастью, это было исправлено давно. До конца прошлого века (я не могу дать вам точную дату). Но определенно до g++ 3.0.

Я подумал о следующем простом способе узнать тип объекта в иерархии.

Вы определили класс по номеру. Это не то же самое, что актерский состав. Вам все еще нужно преобразовать указатель в правильное местоположение.

Может кто-нибудь объяснить, может ли это быть медленнее, чем dynamic_cast?

Я подозреваю, что вам будет трудно написать версию быстрее, чем текущая реализация. Особенно учитывая все особые угловые случаи с виртуальным наследованием и тому подобное. Если честно, я сомневаюсь, что вы могли бы сделать быстрее даже для простой иерархии, как вы показываете. У компилятора есть 30-летние приемы оптимизации. Эти приемы применяются во время компиляции, а ваш результат - во время выполнения.

учитывая, что скорость является худшим недостатком C++ по сравнению с C?

Мне трудно в это поверить. У вас есть цитата?

Другие вопросы по тегам