1. C++ / Говнокод #12038

    +23

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 96
    97. 97
    98. 98
    99. 99
    #include <iostream>
    #include <stdlib.h>
    #include <typeinfo>
     
    using namespace std;
     
    #define ololo for(volatile register int i=0;i<10;++i);
     
    struct VB
    {
            virtual void f() const =0;
    };
     
    class V1: public VB
    {
            void f() const {ololo}
    };
     
    class V2: public VB
    {
            void f() const {ololo}
    };
     
    struct TU1
    {
            inline void f() const {ololo}
    };
     
    struct TU2
    {
            inline void f() const {ololo}
    };
     
    struct TUB
    {
            const type_info* type;
            union 
            {
                    TU1 tu1;
                    TU2 tu2;
            };
     
            template<class T>
            void ctor()
            {
                    this->type=&typeid(T);
            }
            
            template<class T>
            inline void call(const T& f)
            {
                    if(this->type==&typeid(TU1))
                            f(this->tu1);
                    else
                            f(this->tu2);
            }
    };
     
    enum {N=1000, N2=N*50};
     
    int main() {
            cout<<"ok"<<endl;
            {
                    VB*v[N];
                    for(int i=0;i<N;++i)
                            if(rand()%2)
                                    v[i]=new V1;
                            else
                                    v[i]=new V2;
                    volatile clock_t a=clock();
                    for(int j=0;j<N2;++j)
                            for(int i=0;i<N;++i)
                                    v[i]->f();
                    volatile clock_t b=clock();
                    cout<< (double)(b - a) / CLOCKS_PER_SEC<<endl;
            }
            cout<<"ok"<<endl;
            {
                    TUB v[N];
                    for(int i=0;i<N;++i)
                            if(rand()%2)
                                    v[i].ctor<TU1>();
                            else
                                    v[i].ctor<TU2>();
                    struct Continuation
                    {
                            inline void operator()(const TU1& a) const {a.f();}
                            inline void operator()(const TU2& a) const {a.f();}
                    } cps;
                    volatile clock_t a=clock();
                    for(int j=0;j<N2;++j)
                            for(int i=0;i<N;++i)
                                    v[i].call(cps);
                    volatile clock_t b=clock();
                    cout<< (double)(b - a) / CLOCKS_PER_SEC<<endl;
            }
            cout<<"ok"<<endl;
            return 0;
    }

    http://ideone.com/plFaLM
    Тут в соседней теме разгорелся спор, что быстрее - полиморфизм виртуальных функций или полиморфизм tagget union. По сути последнее - выбор по if нужной виртуальной функции. Говорят в Java быстрее второе.
    Тема родилась из http://govnokod.ru/12025#comment158188
    Получилось по результатам измерений:
    Виртуальные функции: 1.8 секунд.
    tagget union: 1.94 секунд.
    Притом это всего 2 полиморфных типа в tagget union, а если рост числа полиморфных классов будет расти, то разрыв между виртуальными функциями и tagget union только увеличится. Притом производительность tagget union будет только падать.
    Тема поднята ещё со взглядом на функциональные языки. Это ведь там так модны ADT с постоянным внутри ifподобным паттернматчингом по ним.
    Жду указания на косяки или способы поднять производительность tagget union.

    Запостил: LispGovno, 31 Октября 2012

    Комментарии (94) RSS

    • Элсо мне понравилось:
      volatile register

      Интересно, что это означает в контексте стандарта С++?
      Ответить
      • В контексте стандарта С++ register — это рекомендация. С учетом volatile это равносильно отсутствию register.
        Ответить
    • Вообще ситуация странная. В случае виртуальных функций мы в любом случае получаем stall конвейера процессорных команд, в то время как в случае с if мы стол либо не получаем, либо получаем с веротяностью 50%, а значит производительность второго случая должна быть выше.
      Ответить
      • >if(rand()%2)
        Ты обманываешь рандомом предсказатель переходов. В реальных ситуациях там не 50/50 а какой-то метод дергается чаще.
        А в той же жабе instanceof прекрасно им оптимизируется.

        Ну и сделай штук 5-6 полиморфных классов - интересно посмотреть. Плюс не стоит забывать про кейс. Хотя можно сказать заведомо что сишный кейс - кал.
        Бенчи в ideone - это жестоко.
        Ответить
        • Да не особо важно. Даже если предсказатель переходов в только в 10% случаев угадает, то все равно производительность tagget union по идеи должна быть выше, тк столы будут только в 90% случаев, а у виртуальной функции они в 100%.
          Ответить
          • > а у виртуальной функции они в 100%
            Не в 100%. Для косвенных переходов тоже есть предсказатель, правда, если мне не изменяет память, помнит он только самый последний вызов. Т.е. если дрючить одну и ту же виртуальную функцию - угадает, если разные по очереди - уже нет.
            Ответить
        • >Ну и сделай штук 5-6 полиморфных классов - интересно посмотреть.
          Да полиморфизм виртуальных функций должен ещё больше выиграть. Мне это почему то кажется очевидным, поэтому я ничего не делал. Даже если заюзать деление пополам у if в tagget union. Результаты могут пошатнутся в сторону tagget union только если мало полиморфных классов (типа 2) и притом одна ветка if всегда выполняется много чаще других (например первый полиморфный класс содержится в массиве v много чаще других).
          Ещё наверное сравнение if(this->type==&typeid(TU1)) можно оптимизировать, ибо &typeid(TU1) неплохо бы заменить на константу. Оно константно, но компилятор может превратить это в вызов функции.
          Ответить
          • >> Мне это почему то кажется очевидным, поэтому я ничего не делал.
            Да мне тоже много чего казалось очевидным, пока не начал креститься проверять лично.

            PS> Внезапно на хабре сделали хороший, добротный тест:http://habrahabr.ru/post/118087
            Ответить
            • > пока не начал креститься
              это к Тарасу
              Ответить
            • Там производительность мультиметодов измеряли. Немного не то. Хотя близко конечно.
              Ответить
              • В жабе нет мультиметодов - их эмулировали полиморфизмом.
                И он соснул.
                Ответить
                • Кстати, вот я смотрю, возможно стоит ещё и inline убрать, особенно с методов TUi. Естественно ключевое слово не достаточно убрать, нужно вынести вне класса реализацию функции.
                  Ответить
    • http://liveworkspace.org/code/623071985a5b2a46dee380b8fa2586b1

      virtual functions: 1.94 сек
      tagget union: 1.6 сек
      Видимо зависит от проца.
      Мы кажется выяснили, что на IDEONE - AMD.
      Возможно на liveworkspace.org - Intel или более древний\более новый AMD.
      Ответить
      • Just as planned.
        И повторюсь - делать бенчи в online ide - это конечно хардкор.
        Ответить
    • Таки здесь не хватает Лиспа.
      Ответить
    • Боже мой, почему нельзя просто писать программы, без всех этих извращений?
      Ответить
      • Надо книгу написать: "Программирование на C++ без извращений".
        Ответить
        • в которой будет 200 пустых страниц?
          Ответить
          • Будет список всех отличий от чистой сишки и везде приписки "НЕ ИСПОЛЬЗУЙТЕ ЭТУ ВОЗМОЖНОСТЬ".
            Ответить
            • Это какая из возможностей сишки тебе нужна? Наверное вывод типов?
              stroka="Hello world!";
               
              SubStringStartWith(Char, String)
              {
                      return strchr(String, Char);
              }
               
              #define cl 'w'
               
              main() 
              {
                      printf("In character literal \'%c\' %d bytes \n", cl, sizeof(cl));
                      printf("In string \"%s\" substring, that start with \'%c\' char is \'%s\'", stroka, cl,  SubStringStartWith(cl, stroka));
                      return 0;
              }
              http://ideone.com/ICydFM
              Ответить
              • Что-то мне подсказывает, что сишный вывод типов всегда выводит int
                Ответить
                • Правильно подсказывает.
                  Ответить
                  • В strict c99 не компилится
                    Ответить
                    • яркий пример, когда принятие нового стандарта серьезно ухудшает язык
                      потому то микрософт мерзкий с99 никогда не внедрит
                      Ответить
                      • А есть 2 стандарта strict c99 и с99?
                        Ответить
                        • нет, есть c11, с99 и ansi c (c89)
                          микрософт, как обычно, поддерживает только все самое последнее
                          Ответить
                          • > есть c11, с99 и ansi c (c89)
                            > поддерживает только все самое последнее
                            т.е. c89?
                            Ответить
                        • 3: кроме strict есть ещё transitional (c99 по умолчанию) и frameset
                          Ответить
                          • transitional, frameset
                            А в чем особенности этих?
                            Ответить
                          • как бы насчет transitional и strict понятно из названий что это за стандарты. а вот про frameset я не понял. что-за фреймы?
                            Ответить
        • >Надо книгу написать:
          "Как программировать на C++ без извращений?".
          В конце книги вывод: "Это очень просто. Не программировать на С++".
          В главе "Благодарности и пожелания автору от рецензентов": "Как можно проще программируйте на С++ и не будьте таким развратным."
          Ответить
      • А вы знаете такой язык, где оптимизация tagget union доступна в дефолтной поставке языка, имеющая требуемую эффективность и не требующая от программиста каких-либо усилий?
        Ответить
        • С каких это пор tagged union является оптимизацией?
          Ответить
          • оптимизация по памяти
            Ответить
            • И сколько байт это позволяет соптимизировать?
              Ответить
              • Это позволяет оптимизировать размещение данных.
                Ответить
                • Каким образом?
                  Ответить
                  • Даже я знаю!!! Гарантируя то, что в одно и то же время два объекта не будут использоваться. Т.е. можно задействовать память от неиспользуемого под какие-то свои нужды, она все равно не нужна программе.
                    Ответить
                    • И часто такое нужно?
                      Ответить
                      • Капитан Крестоблядство говорит, что да.
                        Не, я тоже нихуя не понял, что wvxvw имел в виду.
                        Ответить
                        • > Не, я тоже нихуя не понял, что wvxvw имел в виду.
                          Like ordinary unions, tagged unions can save storage by overlapping storage areas for each type, since only one is in use at a time.
                          Ответить
                          • Ты не в теме.
                            Полиморфные объекты тоже это умеют.
                            А вот структуры, которые могут одновременно хранить и Derived1, и Derived2, жрут лишнюю память, и про "использовать память под полезные нужны" имелось в виду именно в сравнении с простыми структурами.
                            И да, если разные ветки имеют ооочен разные размер, то полиморфные объекты могут дать выигрыш по памяти, потому что они всегда жрут сколько надо, и тегоюнион жрёт память в соответствии с размером самой длинной ветки.
                            Ответить
                      • Оптимизация tagged union нужна для:
                        1)Убирания долгой аллокации объекта по new из кучи.
                        2)Добавление кешфрендли объекту, тк нет отделения большим диапазоном адресов таблицы виртуальных методов от RTTI от самого объекта и от указателя на него.
                        3)Частичное убирание stall в конвейере команд процессора.

                        Пункт 1) также можно реализовать и через placement new в объекте подобном TUB (там внутри подобный унион или массив с размером максимального объекта, который можно разместить в TUB).
                        Может ещё кто-то знает назвначение подобной техники. Хотя конечно это бы оформить в библиотеку с кодогенерицией, а то сейчас выглядит паршиво как говнокод.
                        Ответить
                        • зачем там прямо уж кодогенерация?
                          http://www.boost.org/doc/libs/1_51_0/doc/html/variant.html
                          Ответить
                          • >зачем там прямо уж кодогенерация?
                            Инстанцирование шаблона класса - создание кода класса на основе шаблона (кодогенерация).

                            >boost.org/doc/libs/1_51_0/doc/html/variant
                            больше 12 байт объекты не размещаются в boost::variant. Он выделяет объекты в куче с соответствующими последствиями.
                            Ответить
                          • boost::variant с его boost::get не даёт возможность сделать O(log n) выбор нужного типа. Только О(n). Код, что выше, особенно если его сделать через хорошую крестовую кодогенерацию - позволяет сделать выборку нужной функции за O(log n) или даже за О(1). Для этого просто нужно сгенерировать нужный код для функции
                            template<class T>
                            inline void call(const T& f)
                            Ответить
                            • Есть конечно функция boost::apply_visitor но про сложность этой функции стыдливо умалчивают.
                              Ответить
                              • минусы расставил не я
                                однако мне тоже интересно откуда дровишки
                                1) про 12 байт
                                2) O(log n) vs O(n) если там вообще compile-time

                                ну а про сложность (которая также compile-time) тоже интересно
                                ну разве что компилятору сложно - ну а кому в наше время легко

                                может я чего упустил?
                                Ответить
                                • > минусы расставил не я
                                  Пора уже показывать над минусами тех, кто их поставил.

                                  Сложность, если конечно не ошибаюсь, там действительно O(1) т.к. get() это проверка на соответствие запрашиваемого и реального типа да тупой каст.
                                  Ответить
                                  • это вообще в any делается проверка типа
                                    в variant там все решается через перегрузку
                                    типа такой:
                                    .
                                        T& operator()(T& operand) const
                                        {
                                            return operand;
                                        }
                                    
                                        template <typename U>
                                        T& operator()(U&) const
                                        {
                                            // logical error to be here: see precondition above
                                            BOOST_ASSERT(false);
                                            return ::boost::detail::variant::forced_return< T& >();
                                        }
                                    Ответить
                                    • > это вообще в any делается проверка типа
                                      > в variant там все решается через перегрузку
                                      типа такой:

                                      The get function allows run-time checked, type-safe retrieval of the content of the given variant.

                                      Все-таки рантайм проверка там есть.
                                      Ответить
                                      • для примера выше для
                                        foo & f = boost::get<foo>(v);
                                        f.print();
                                        студия в Release сгенерила вот такой код:
                                        00EF100E  push        esi  
                                                boost::variant<foo, bar, baz> v = foo();
                                                printf("sizeof(v) = %u\n", sizeof(v));
                                        00EF100F  mov         esi,dword ptr [__imp__printf (0EF209Ch)]  
                                        00EF1015  push        324h  
                                        00EF101A  push        offset string "sizeof(v) = %u\n" (0EF20FCh)  
                                        00EF101F  call        esi  
                                        
                                                foo & f = boost::get<foo>(v);
                                                f.print();
                                        00EF1021  push        offset string "foo!\n" (0EF20F4h)  
                                        00EF1026  call        esi  
                                        
                                                return 0;
                                        }
                                        если это O(1) выбор в компайл-тайм, то я не знаю

                                        ран-тайм - имеется в виду, что при несоответствии типов будет в рантайме кинуто bad_get, а не ошибка компиляции
                                        Ответить
                                        • > если это O(1) выбор в компайл-тайм, то я не знаю
                                          А это походу потому, что она видит что туда засунули. Попробуйте сделать тип зависящим от чего-нибудь типа argc - если 1 то foo() если 2 то bar(). Тогда, мне кажется, она вставит проверочку с вбросом bad_get.

                                          http://liveworkspace.org/code/468230da8ae63feab65e99bede607fbd
                                          Ответить
                                  • >Сложность, если конечно не ошибаюсь, там действительно O(1) т.к. get() это проверка на соответствие запрашиваемого и реального типа да тупой каст.

                                    Лол. У тебя же n классов в иерархии. И если ты не знаешь, какой там лежит класс в boost::variant, то у тебя n * O(1). То есть О(n).
                                    А так я думаю очевидно, что boost::get работает за О(1).
                                    Ответить
                                    • @bormand
                                      > Тогда, мне кажется, она вставит проверочку с вбросом bad_get.
                                      да, одну проверочку вставит, а не O(n)
                                      @LispGovno
                                      > И если ты не знаешь, какой там лежит класс в boost::variant, то у тебя n * O(1)
                                      boost::variant<int, long, char, bool, double, foo, bar, baz> v;
                                              
                                      if (argc == 1)
                                      	v = baz();
                                      else if (argc == 2)
                                      	v = bar();
                                      
                                      boost::get<baz>(v).print();
                                      утверждается, что для такого variant должно произойти 8 проверок, прежде чем мы убедимся, что тип == baz
                                      однако:
                                      boost::get<baz>(v).print();
                                      00051082  mov         ecx,dword ptr [esp+18h]  
                                      00051086  test        ecx,ecx  
                                      00051088  jns         main+81h (51091h)  
                                      0005108A  or          eax,0FFFFFFFFh  
                                      0005108D  sub         eax,ecx  
                                      0005108F  jmp         main+83h (51093h)  
                                      00051091  mov         eax,ecx  
                                      00051093  jmp         dword ptr  (510E0h)[eax*4]  
                                      $LN261:
                                      0005109A  lea         ecx,[esp+0Ch]  
                                      0005109E  call        dword ptr [__imp_std::exception::exception (520ACh)]  
                                      000510A4  push        offset __TI2?AVbad_get@boost@@ (523C8h)  
                                      000510A9  lea         eax,[esp+10h]  
                                      000510AD  push        eax  
                                      000510AE  mov         dword ptr [esp+14h],offset boost::bad_get::`vftable' (5214Ch)  
                                      000510B6  call        _CxxThrowException (51E80h)  
                                      $LN264:
                                      000510BB  push        offset string "baz!\n" (52140h)  
                                      000510C0  call        dword ptr [__imp__printf (520A4h)]
                                      Ответить
                                      • >boost::variant<int, long, char, bool, double, foo, bar, baz> v;
                                        утверждается, что для такого variant должно произойти 8 проверок, прежде чем мы убедимся, что тип == baz


                                        Ну конечно. Ты сначала проверяешь через boost::get на int, потом на long, потом на ... и так до конца. Если ты что-то знаешь, то ты естественно часть проверок через boost::get опускаешь. В данном коде выше ты знал, что у тебя там baz лежит и сделал лишь одну проверку:
                                        boost::get<baz>(v).print();
                                        Другие варианте тебе были просто не нужны.

                                        Фактически про О(n) я говорил, когда ты через boost::get моделируешь полиморфизм.
                                        Ответить
                                        • > когда ты через boost::get моделируешь полиморфизм.
                                          ладно
                                          закрывая этот вопрос окончательно - ты имеешь в виду visitor для объекта variant - будем эмулировать полиморфизм
                                          http://liveworkspace.org/code/374baab33e4f8e969fec16f3119f5345
                                          вот этот код, как ни крути, у меня в релизе без оверхеда сразу выбирает нужный operator ()
                                          Ответить
                                          • >visitor
                                            Наконецто. Я о нем уже несколько раз в этом треде писал и о его проблемах.
                                            Ответить
                                            • о каких его проблемах?
                                              всё что ты написал - ты не разобрался как он работает
                                              Ответить
                                              • Где я такое написал? Ты наверное тред не читал.

                                                Я сказал, что стратегию под оптимизацию другую выбрать нельзя визиторе, если профлаер указал на несостоятельность текущей стратегии поиска реального типа класса.

                                                И ещё проблема, что не известно какая стратегия там вообще по умолчанию используется, если в исходники не заглядывать, тк в документации это не указано.
                                                Ответить
                                          • Как ты в лайвворкспейс.орг задаешь входные параметры программы? Или пользуешься дефолтом и там менять их нельзя?
                                            Ответить
                                          • >вот этот код, как ни крути, у меня в релизе без оверхеда сразу выбирает нужный operator ()

                                            С чего ты взял что без оверхеда? Что там? O(1), O(log n) или всеже O(n)?

                                            На счет O(1) я уверен, что оно там не используется, если смотреть на размер boost::variant. Значит там или O(log n) или О(n)
                                            Ответить
                                            • > С чего ты взял что без оверхеда?
                                              запустил в Release, но с /Zi /DEBUG
                                              поставил бряку на apply_visitor и по асм коду (alt+8) прошелся f11
                                              на любых исходных данных компилятор переходит в нужный обработчик за одну проверку
                                              вникать в шаблонодебри сорцов варианта в первом часу ночи уже не хочется

                                              edit
                                              > за одну проверку
                                              да там и нет в асм коде вообще ни таблицы сравнений, ни последовательности сравнений по списку
                                              сразу куда нужно переходит - оверлоад, мать его
                                              Ответить
                                              • > за одну проверку
                                                а, может быть, виноват хороший оптимизатор
                                                так что надо будет еще потестировать завтра
                                                Ответить
                                              • >да там и нет в асм коде вообще ни таблицы сравнений, ни последовательности сравнений по списку
                                                сразу куда нужно переходит - оверлоад, мать его


                                                Может это компилятор соптимизировал, раз знает, какой реально тип там лежит во время компиляции? К параметрам командной строки привезал тип, как ты делал выше?

                                                Если исключил воможность оптимизации со стороны компилятора, то это довольно странно. Почему за О(1)?..
                                                Ответить
                                                • докопался в целом как работает visitor (у меня дома вообще буст 1.47, оказывается, так что не скажу за латест вершион)
                                                  внутри variant хранится which - число - навроде "индекс" типа из шаблонного списка
                                                  apply_visitor в итоге строит конструкцию switch для вызова хендлера по конкретному индексу среди всех типов внутри variant - так что уж тут как компилятор отработает этот свич, такой O и будет (да, O(n) в худшем случае, то там return на каждую ветвь, так что оптимизатору есть где поработать)

                                                  ну а на /O2 микрософтовский компилер всю эту байду сокращает до банальщины - заранее кладет в стек нужные адреса при инициализации для каждого возможного argc (выбор из например 4 типов-то для 2 переменных не очень велик) и затем по конкретному argc где надо сразу достает нужные смещения и делает вид, что O(1) и так и задумано
                                                  Ответить
                                                  • Вот до чего техника дошла... На самом деле создатели
                                                    буст:вариант
                                                    молодцы. Хоть стратегию поменять нельзя, но зато есть где развернутся оптимизатору. Уважуха.

                                                    goto буст;
                                                    Ответить
                                • даже не поленился проверить насчет псевдо 12 байт
                                  http://liveworkspace.org/code/195391c0a3ddf544bf621ce16b0a316b

                                  cstdio включен чтобы было легче разбираться в асме
                                  Ответить
                                  • >даже не поленился проверить насчет псевдо 12 байт

                                    Или этого больше нет в новых версиях, или это было в некоторых реализациях, либо так было реализовано в boost::any. Я склоняюсь к последнему.
                                    Ответить
                                • >2) O(log n) vs O(n) если там вообще compile-time
                                  > ну а про сложность (которая также compile-time) тоже интересно


                                  Уж и не знаю что там со сложностью компилетайм, а вот сложность поиска находящегося в варианте класса из иерархии О(n), если он не известен через boost::get. В своей же реализации (например как в говнокоде выше) можно организовать поиск нужного класса в иерархии за О(log n), O(1) и О(n) с переборам классов в соответствии с вероятностью их появления. Через boost::get конечно тоже можно перебрать за О(n) с учетом вероятности, но это не удобно делать каждый раз, ибо перебор приходится харкодить везде по коду и если профлаер скажет поменять данный перебор, то придется менять вообще везде вручную возможно с ошибками. А так выбрал реализацию call нужную (в том числе и сгенерировал её код на крестах через метапрограммирование) и если профлайер скажет, мол медленно - ты сможешь поменять стратегию сгенерированного кода для call из говнокода выше.

                                  А boost::apply_visitor не известно как работает и менять стратегию в угоду оптимизации не позволяет.
                                  Ответить
                                  • что значит "он не известен через boost::get"?
                                    поясни мысль
                                    когда variant инициализируется, он уже в курсе какой тип он хранит
                                    поэтому в чем проблема для него сделать одну единственную проверку "если тип тот, то на тебе его, если тип не тот - лови эксепшен"
                                    где тут O(n)?
                                    разницу между any и variant улавливаешь?

                                    из мануала:
                                    > Boost.Variant provides compile-time checked visitation of its content.
                                    какая еще стратегия? O(1)
                                    Ответить
                                    • Посмотри на код выше в говнокоде этого треда? Там моделируется полиморфизм и какой из классов TUi лежит как-бы в базовом классе TUB совершенно не известно, поэтому там проверка может быть вида цепочки if за О(n), может быть провера вида О(log n), и даже О(1).

                                      А вот с твоим boost::get каши не сваришь. Он потребует проверку O(n) для перебора всей иерархии классов в любом случае, если ты моделируешь полиморфизм и не знаешь какой реальный тип из списка дозволеных, лежит в boost::variant.
                                      Ответить
                  • Заводишь массив тэгованных структур вместо массива указателей на базу. Таким образом, все нужные данные размещены в одном куске памяти.
                    Ответить
                    • Да, именно это демонстрирует плюс пункта 2, из того, что я перечислил. Хорошо для всяких приставок (SPS / XBOX и тд) для игр и прочей аппаратуры с говнокешем в цп.
                      Ответить
                      • >и прочей аппаратуры с говнокешем в цп
                        Intel Core Architecture?
                        Ответить
                        • Ты хочешь сказать, что в Intel проблемы с кешем? Я считал, что он с ним хорошо работает.
                          Ответить
                        • Кстати, а зачем тебье вдруг понадобилась оптимизация, подобная этой, на Java через instanceof? Неужели на бутленёк наткнулся?
                          Ответить
                          • Не. Дело в следующем. В мире жабы практически все активно форсят стиль написания кода где используется ООП и полиморфизм в частности.

                            Давно по незнанию я также писал такой код, несмотря на его определенную громоздкость, считая что где-где, а в JVM там-то всё оптимизировано.
                            Ну и по ходу дела старался избегать instanceofов и прочих ifов с кейсами даже там где они были необходимы (правда кейсы - не очень, обычно их можно заменить мапом или обычным массивом).

                            Казалось бы взять адрес класса, найти метод в таблице, сделать call. Что может быть проще?
                            Наверное это таки быстрее чем проверять бранч на 10 условий.
                            Но вконец я в душе ненавидя ооп-парадигму, т.н. паттерны и громоздкость порождаемого ими кода, решил проверить "а велик ли прирост скорости от полиморфизма".
                            Ответить
                          • Тут стоит отметить, что несмотря на полиморфизм, эти самые полиморфные объекты в мире долбоебов-оопешников с мозгом засраном под завязку паттернами принято конструировать через фабрики.
                            И выглядят они примерно таким вот образом:
                            static IShitable buildSomeShit(OrderEnum type){
                               switch(order){
                               case SHIT: return new Shit();
                               case GOOMNO: return new Goomno();
                               case SSAKI: return new SSAKI();
                               default: throw new Exception("В сортах говна не разбираюсь!");
                               }
                            }

                            Как мы видим это тот же кейс, от которго мы избавились с помощью полиморфизма, но только вот он всплыл в другом месте! Его перенесли в фабрику.
                            Еще есть способ: поднятие объектов по рефлексии, где из мапа достается класс объекта, но это в какой-то мере хак, причем тормозной.
                            Ответить
                            • > И выглядят они примерно таким вот образом
                              Не, в правильной фабрике ещё воткнута регистрация с привязкой идентификатора типа к прототипу.

                              > долбоебов-оопешников с мозгом засраном под завязку паттернами
                              Паттерны по сути весьма забавная штука: они позволяют заменить 20 строк копипасты 40 строками разного кода
                              Ответить
                              • > Паттерны по сути весьма забавная штука: они позволяют заменить 20 строк копипасты 40 строками разного кода

                                Ох ты ж сукин сын, да это то, что меня всё время мучало на интуитивном уровне и я долго пытался как-то выразить, но не мог подобрать слова. Это надо вынести в крылатые фразы говнокода.
                                Ща ещё виртуалами плюсану ^_^
                                Ответить
                                • А ты тоже сукин сын!
                                  Я только хотел писать коммент про подсознательное, интуитивное восприятие того что Роман выразил словами.
                                  И про то что надо это где-нибудь на видном месте выбить в граните.
                                  Ответить
                          • И значит это меня порядком достало и я решил сравнить раз и навсегда.

                            По факту выяснилось что Тарас был глубоко прав, постоянно кормя говном фанатов ооп.
                            Хоть большинство и считают это зеленью, но он-то прав.
                            Ответить
                            • 146% публики считают Тараса зеленью. Собственно, это и есть признак того, что он прав, без союза "но".
                              Ответить
                    • Кстати, говорят Ada может в красивые tagget union. Не покажите примеров работы с ними? Увеличивает там это производительность?
                      Ответить
                      • Обычные tagged union. Производительность в отладочном режиме проседает, потому что вместо foo.bar генерируется
                        if foo.tag /= tag_bar then throw Discriminant_Error; end if;
                        foo.bar;
                        В выпуске проверку можно убрать в бутленьке, если он хорошо проверен. Проверку можно убрать и в кулхацкерских целях.
                        Ещё в них разрешено пихать неподы. Потому что легко определить, какой из неподов, находящихся в разных ветках по одному адресу, надо убрать - посмотреть в тэг
                        Ответить
                        • Я сно. О(log n) или О(1) они при выборе нужно го класса они не осилили. Только О(n). Интересно как с этим в ADT функциональных языков? О(n) при матче или лучше?
                          Ответить
                          • > О(log n) или О(1) они при выборе нужно го класса они не осилили

                            Что за хуйню ты мелешь?
                            Там всё за O(1), что там может быть за O(n)?
                            Ответить
    • > if(this->type==&typeid(TU1))

      Я тут узнал недавно, что typeid считается в рантайме.
      Поэтому сделай, пожалуйста, нормальный свич и явный тэг.
      Ответить

    Добавить комментарий