На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (4) « Первая ... 2 3 [4]  все  ( Перейти к последнему сообщению )  
> насколько тормозной dynamic_cast?
    Ну собственно я про это и написал. Как ещё проверить находится ли один узел в поддереве другого. Единственный эффективный способ спуститься по дереву иерархии от наследника к предку. Мы либо наткнёмся на переданный класс и выполним приведение, либо дойдём до конца иерархии, так и не встретив переданного класса, и вернём ноль, в знак того, что приведение невозможно. Это при одиночном наследовании.
    Можно развернуть цикл спуска в точке приведения, проверка будет быстрее. Кроме того, так можно прервать проверки до достижения самого корневого класса (переданный в dynamic_cast указатель сам может быть производным, и его базовые классы проверять незачем).
    При множественном наследовании при скольжении по дереву возможно несколько продолжений. Однако только одно может вести к классу передаваемого указателя. В этом случае развёртывание цикла даёт даже больший эффект, так как не приходится перебирать варианты продолжений.
      По-моему, вы упускаете из виду такой вариант, или я вас не так понял:
      ExpandedWrap disabled
        class IInterface1 { /* ... */ };
        class IInterface2 { /* ... */ };
         
        class MyClass: public IInterface1, public IInterface2 { /* ... */ };
         
        void foo(IInterface1* pInt1)
        {
          /* ... */
         
          IInterface2 pInt2 = dynamic_cast<IInterface2*>(pInt1);
         
          if (pInt2 != 0)
          /* ... */
        }
      Перекрёстное приведение – часто встречающаяся фича. Класс может реализовывать несколько интерфейсов, и нередко встаёт задача проверки того, поддерживает ли он тот или иной интерфейс, и делается это перекрёстным приведением. Причём тут ещё простой пример.

      P.S. Говоря об обходе графа, я не преувеличивал.
      Сообщение отредактировано: Qraizer -
        Цитата Qraizer @
        Перекрёстное приведение – часто встречающаяся фича.
        Вот тут согласен. В этом случае выглядит практически нереальным во время компиляции угадать цепочку приведения. Значит остаётся только бродить по графу разыскивая нужный маршрут. И это достаточно медленный процесс, особенно в случае неудачи.
          Цитата Qraizer @
          По-моему, вы упускаете из виду такой вариант, или я вас не так понял:

          Я лишь хотел уточнить, что несмотря на обобщенное название темы, автора (в первую очередь) интересует конкретная простая ситуация, когда за номинальным
          базовым типом ObjectBase* скрывается реальный объект типа XObject*, к которому и нужно выполнить dynamic_cast (см.#1 и пояснение в #8). Поэтому прежде чем разглагольствовать на общие темы (на 4 страницах), следовало бы пояснить, что в данном конкретном случае dynamic_cast выполняется максимально быстро (за одно сравнение typeid реального типа с требуемым).
            Цитата leo @
            Я лишь хотел уточнить, что несмотря на обобщенное название темы, автора (в первую очередь) интересует конкретная простая ситуация, когда за номинальным
            базовым типом ObjectBase* скрывается реальный объект типа XObject*, к которому и нужно выполнить dynamic_cast (см.#1

            Да, действительно, меня интересовала конкретика. Но ради понимания общего механизма, на будущее, все остальные объяснения, тоже были интересны.
              Цитата leo @
              за одно сравнение typeid реального типа с требуемым
              Сравнений может быть и больше. Приведение нормально выполняется ещё и в случаях, когда реальный тип оказывается наследником требуемого. А это можно выяснить только пробежав по всей цепочке наследования от реального типа к требуемому.
                Цитата amk @
                Приведение нормально выполняется ещё и в случаях, когда реальный тип оказывается наследником требуемого.

                Это уже обобщение. Я говорю о конкретном случае (см.#1 и #8), когда dynamic_cust выполняется не "от балды", а только после предварительной проверки типа объекта по уникальному идентификатору типа Category (или по тому же tipeid). Если автор обобщит задачу и будет присваивать одно значение Category двум и более наследуемым классам, то да - проверка будет выполняться по цепочке "от реального типа к требуемому". А пока у него реальный тип = требуемому, проверка при dynamic_cust выполняется за одно сравнение.
                  Цитата leo @
                  Если автор обобщит задачу и будет присваивать одно значение Category двум и более наследуемым классам, то да - проверка будет выполняться по цепочке "от реального типа к требуемому". А пока у него реальный тип = требуемому,
                  проверка при dynamic_cust выполняется за одно сравнение.

                  У меня category выставляется полуавтоматически. Собственно я завёл её как раз ради такой или подобной идентификации. Например, чтобы из списка разных объектов, быстро выбрать объекты нужных категорий.
                  Но в некоторых местах, получилось весело и неоднозначно.
                  У меня есть ромбовидная иерархия...

                  ExpandedWrap disabled
                    ]
                    class ObjectBase abstract
                    {}
                     
                    class XObject:
                    public virtual ObjectBase
                    {};
                     
                    class YObject:
                    public virtual ObjectBase
                    {};
                     
                     
                    class XYObject final:
                    public XObject,
                    public YObject
                    {
                    };


                  Причём объекты нужны и могут быть типов XObject, YObject или XYobject.

                  В первом сообщении, я спрашивал лишь про один фрагмент. Но оно действительно для всех классов.
                  Несколько функций работают только с XObject или YObject.
                  Понятно и допустимо, что они будут работать с XYObject.
                  Но моя первоначальная функция приведения, точнее проверки категорий, ломались на таком. Пришлось делать идентификаторы из битовых флагов.

                  ExpandedWrap disabled
                    enum class ObjectCategory
                    {
                    XObject = 0x0011,
                    YObject = 0x0012,
                    XYObject = 0x0013
                    };


                  Ну и проверка, соответственно уже проверяла маску, а не полное равенство.
                  Ох и морока же. Была мысль заюзать std::bitset или switch. Но остановился на битовых флагах.

                  И да в предыдущем варианте тестирования, кроме приведение типа объекта, к его реальному типу, делалось соответственно приведение к одному из базовых типов. Если реальный объект XYObject, а нужен только XObject, указатель же вообще ObjectBase...
                  Но даже в этом случае, всё отрабатывало быстро и чётко.

                  Как я понимаю, сначала dynamic_cast смотрел VMT и обнаружив там XYObject, спускался вниз по иерархии, проверяя либо XObject либо YObject.
                    Дружище, на сколько я понял, был главный вопрос этот:
                    Цитата Eric-S @
                    но насколько это плохо?
                    Можно "копья ломать" еще стопицот страниц. Домыслы, догадки. Но решение в каких-то числах, пусть в шкальных оценках, ИМХО, тебе дадут тесты. Сделай пару-тройку синтетических примеров с разветвленным множественным наследованием, замерь на таймере высокого разрешения - и ты получишь, как минимум, порядок в разности скоростей. Чесслово, рассуждений выше для тестов - выше крыши. А вот численный результат, уверен, был бы любопытен всем :)
                      Цитата JoeUser @
                      Но решение в каких-то числах, пусть в шкальных оценках, ИМХО, тебе дадут тесты.

                      Пытался замерять такты, через clock().
                      там значения плавали, для одного и того же кода. При этом два диапазона значений, для двух разных кодов, были довольно близкими. Я не смог однозначно сказать, что какой-то код быстрее. Субъективно же чуточку ускорилось.
                      Следовало сразу мерить профайлером, в более суровых и чистых условиях, а теперь поздняк метаться. На данный момент у меня нет действющих dynamic_cast.
                        Цитата Eric-S @
                        Я не смог однозначно сказать, что какой-то код быстрее. Субъективно же чуточку ускорилось.

                        На большлом компе проверял? проверь на железке с памятью 2М, и скоростью
                        машины времен начала 90-х, хотя бы.Либо каждый замен времени умножай на 100 или 1000,
                        и сравни есть ли разница, это че совсем точно,но лучше чем никак.
                          Цитата settler @
                          Либо каждый замен времени умножай на 100 или 1000,
                          Лучше повторять тест. Подобрать такое количество повторов, чтобы вместе они занимали 1-10 секунд. Тогда по крайней мере паре-тройке цифр в результате можно будет доверять.

                          Цитата Eric-S @
                          там значения плавали, для одного и того же кода. При этом два диапазона значений, для двух разных кодов, были довольно близкими. Я не смог однозначно сказать, что какой-то код быстрее.
                          Значит можно считать, что притормаживание несущественно. В любом случае основное время у тебя занимает обработка после проверки, и на фоне этого времени небольшое притормаживание dynamic_cast будет незаметно.
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0479 ]   [ 17 queries used ]   [ Generated: 29.03.24, 02:35 GMT ]