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

    +14

    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
    #define MAX_MONSTER_ID			600
    #define MAX_ITEM_FOR_MONSTER	40
    
    	for (int j=0; j < 1000; j++)
    	{
    		AllMobItemsDrop[j].MMap			= 0;
    		AllMobItemsDrop[j].MMinLvl		= 0;
    		AllMobItemsDrop[j].MMaxLvl		= 0;
    		AllMobItemsDrop[j].IDropRate	= 0;
    		AllMobItemsDrop[j].IGroup		= 0;
    		AllMobItemsDrop[j].IIndex		= 0;
    		AllMobItemsDrop[j].IMinLvl		= 0;
    		AllMobItemsDrop[j].IMaxLvl		= 0;
    		AllMobItemsDrop[j].ILvlRate		= 0;
    		AllMobItemsDrop[j].IMinOpt		= 0;
    		AllMobItemsDrop[j].IMaxOpt		= 0;
    		AllMobItemsDrop[j].IOptRate		= 0;
    		AllMobItemsDrop[j].ISkill		= 0;
    		AllMobItemsDrop[j].ISkillRate	= 0;
    		AllMobItemsDrop[j].ILuck		= 0;
    		AllMobItemsDrop[j].ILuckRate	= 0;
    		AllMobItemsDrop[j].IMinExc		= 0;
    		AllMobItemsDrop[j].IMaxExc		= 0;
    		AllMobItemsDrop[j].IExcRate		= 0;
    		AllMobItemsDrop[j].IAnc			= 0;
    		AllMobItemsDrop[j].IAncRate		= 0;
    	}
    
    	AllMobArrayMaxItem = 0;
    
    	for (int i=0; i < MAX_MONSTER_ID; i++)
    	{
    		for (int j=0; j < MAX_ITEM_FOR_MONSTER; j++)
    		{
    			ItemsDrop[i][j].MMap		= 0;
    			ItemsDrop[i][j].MMinLvl		= 0;
    			ItemsDrop[i][j].MMaxLvl		= 0;
    			ItemsDrop[i][j].IDropRate	= 0;
    			ItemsDrop[i][j].IGroup		= 0;
    			ItemsDrop[i][j].IIndex		= 0;
    			ItemsDrop[i][j].IMinLvl		= 0;
    			ItemsDrop[i][j].IMaxLvl		= 0;
    			ItemsDrop[i][j].ILvlRate	= 0;
    			ItemsDrop[i][j].IMinOpt		= 0;
    			ItemsDrop[i][j].IMaxOpt		= 0;
    			ItemsDrop[i][j].IOptRate	= 0;
    			ItemsDrop[i][j].ISkill		= 0;
    			ItemsDrop[i][j].ISkillRate	= 0;
    			ItemsDrop[i][j].ILuck		= 0;
    			ItemsDrop[i][j].ILuckRate	= 0;
    			ItemsDrop[i][j].IMinExc		= 0;
    			ItemsDrop[i][j].IMaxExc		= 0;
    			ItemsDrop[i][j].IExcRate	= 0;
    			ItemsDrop[i][j].IAnc		= 0;
    			ItemsDrop[i][j].IAncRate	= 0;
    		}
    		ArrayMaxItem[i] = 0;
    	}

    Рабочий код с одного сервера. Код инициализации класа с заполнением структуры. А ведь это можно было уместить в:
    memset(&AllMobItemsDrop, 0, sizeof(AllMobItemsDrop));
    memset(&ItemsDrop, 0, sizeofe(ItemsDrop));

    Запостил: Killbrum, 31 Января 2013

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

    • А если ItemsDrop в куче храниться будет? одним memset'ом не отделаться
      Ответить
      • а может без если? Чисто по факту? :) А по факту у нас:
        struct sItemsDrop
        {
        short MMap; // #1
        short MMinLvl; // #2
        short MMaxLvl; // #3

        short IDropRate; // #4
        short IGroup; // #5
        short IIndex; // #6

        short IMinLvl; // #7
        short IMaxLvl; // #8
        short ILvlRate; // #9

        short IMinOpt; // #10
        short IMaxOpt; // #11
        short IOptRate; // #12

        short ISkill; // #13
        short ISkillRate; // #14
        short ILuck; // #15
        short ILuckRate; // #16

        short IMinExc; // #17
        short IMaxExc; // #18
        short IExcRate; // #19

        short IAnc; // #20
        short IAncRate; // #21
        };
        sItemsDrop ItemsDrop[MAX_MONSTER_ID][MAX_ITEM_FOR_MONSTER];
        sItemsDrop AllMobItemsDrop[1000];
        Ответить
        • Речь про двумерный массив.
          Ответить
        • Это C++. А значит все эти зануления должны были стоять в конструкторе или методе clear (на случай если надо делать сброс посреди работы, а не только при инициализации), а не торчать непонятно где посреди кода.

          А memset в крестах лучше не юзать. Вот будут там потом какие-нибудь указатели или неPOD'ы, и будет вам море радости от мемсета.

          P.S. А вместо дефайнов можно поюзать const int.
          Ответить
          • всему свои границы
            если бы мне попалась такая структура, регулярно требующая зануления (даже в методе clear), я бы написал memset в этом методе с комментом beware of ogres dirty hacks!
            потому что кресты крестами, а структуру тому же программисту и поддерживать/расширять, который запарится с выявлением всех мест, где же еще надо дописывать строчки = 0 для новых полей
            при желании можно всучить ассерт на is_pod, конечно
            Ответить
            • Ну memset() в методе clear() это совсем другое дело. Там при необходимости можно будет и доинициализировать переменные в которых нужны не нули, и указатели почистить если они были... А делать неинкапсулированные грязные хаки типа предложенного постером - как-то стрёмновато.

              > который запарится с выявлением всех мест, где же еще надо дописывать строчки = 0 для новых полей
              Вот в этом у жабы и паскаля есть плюс и минус по сравнению с крестами. Плюс - всегда понятно что по дефолту лежит в полях, и не надо всех этих мемсетов и занулений. Минус - оно, конечно же, медленнее.
              Ответить
            • кстати, на тему PODов. В C++11 разделили на типы со стандартным размещением, и на тривиальный типы. А я вот недавно собирал проект старым GCC 4.2.2 вроде и он ругнулся у меня на offsetof() для типа, у которого есть конструктор, хотя виртуальных методов нет. И даже базового класса нет. В новых 4.7.2 уже не ругается.
              Ответить
              • offsetof?
                есть обстоятельства?
                Ответить
                • это была такая завуалированная попытка получить адрес поля в классе.
                  int* GetField( void* p )
                  {
                     char* c = static_cast<char*>(p);
                     char* c1 = c + offsetof( S, i );
                     return reinterpret_cast<int*>( c1 );
                  }

                  Вместо
                  int* GetField( void* p )
                  {
                     S* s = static_cast<S*>(p);
                     return &(s->i);
                  }

                  Для
                  struct S
                  {
                     S( int i ) : i(i) {}
                     int i;
                  };
                  Ответить
                  • Но зачем?
                    Ответить
                    • зачем адрес поля? нужно для последующих ф-ий. Правда нужен void*, поэтому приведения некоторые лишние.
                      Ответить
                      • Нет. Зачем это делать первым способом, если работает вторым, и второй смотрится получше?
                        Ответить
                  • ничего подозрительным не кажется?
                    Ответить
                    • в каком случае? или вообще?
                      Ответить
                      • ну приводить void * к указателю на структуру, а потом искать в этой структуре поле
                        и это всё заворачивать в метод
                        Ответить
                        • В метод GetField это завернуто исключительно для демонстрации. По сути требовалось из большой структуры извлечь поле, которое будет использоваться как вторичный индекс таблицы БД.
                          Ответить
              • Паrни!
                std::is_trivial и естественно std::is_pod экземпляры классов можно перемещать memmove и memcpy и занулять memset.
                А std::is_standard_layout нахер нужен?
                Ответить
                • судя по cppreference:
                  по нему можно делать грязные хаки с offsetof так, что это не приведет к UB
                  и => делать предположения насчет адреса его первого члена относительно адреса самого объекта
                  Ответить
                  • Почему в
                    struct A {
                        int m;
                    };

                    можно делать эти предположения, а в
                    struct B {
                        int m1;
                    private:
                        int m2;
                    };

                    уже нельзя?
                    Ответить
                    • наверное, потому что нет гарантии, что m2 будет расположено после m1?
                      Ответить
                      • собсно, в c++11 standard layout означает то, что этот объект будет выглядеть в памяти, как аналогичный сишный
                        trivial означает, что его инициализация тривиальна
                        ну а pod = trivial + standard layout
                        Ответить
                        • Это понятно. Почему нет этой гарантии? Ведь спецификатор доступа должен влиять только на видимость?
                          Ответить
                          • c++03 - 9.2.12
                            c++11 N3242 - 9.2.15

                            Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (11).
                            Ответить
    • Пффф... какое сложное общество >_<. Зачем додумывать вот это "если" ? Мы на дебаге? Нам надо написать универсальную ф-цию в которой будем учитывать все возможные и не возможные проблемы? Давайте еще напишем многомилионный враппер для инициализации структуры. Для тех кто в танке:
      1) инициализация = конструктор класса (как минимум в данном коде).
      2) кроме того куска там больше НИЧЕГО не было. Никаких выделений памяти и т.д.
      3) сама структура статичная и имеет только 1 экземпляр
      4) класс статичный и имеет только 1 экземпляр
      5) код рабочий и сдан "в реализ". Но код сильно тормозит и грузит ЦПУ. Суть была оптимизировать код.
      6) суть была в том что есть 3 цикла которые, фактически вручную, забивают нулями. Никто не пробовал посчитать тики процессора? Попробуйте сколько тиков на 3 цикла с 3мя временными переменными и сколько на простой мемсет
      7) суть была в том что при добавлении данных в стуктуру надо бежать и дописывать вот такое вот зануливание. И так каждый раз.
      8) суть была в том что вот эта хрень занимает лист А4 и видя такое в коде начинает хватать кондратий

      P.S. жду минусов
      Ответить
      • > P.S. жду минусов
        Недождешься. Буду вести конструктивную беседу.

        Написал небольшой бенчмарк - двойной цикл до 600 и до 40 и зануление 21 поля на каждой итерации (как в вашем нижнем цикле). И аналогичный бенчмарк для мемтеста того же самого массива. Результаты (10к итераций, gcc 4.6.3, амд 2ГГц) - мемсет 12.3с, циклы 27.3с. Разница всего в два раза.

        > 3мя временными переменными
        -O2, не, не слышал? Счетчики циклов чуть реже чем всегда попадают в регистры.

        Говно тут не в очистке циклами, а архитектуре, из-за которой вообще возникла необходимость часто (если бы это было только при старте - на 2.7мс на довольно хреновом компе всем было бы похуй, и этот код бы тут не оказался) чистить большую структуру фиксированного размера (600х40 элементов).

        > суть была в том что вот эта хрень занимает лист А4 и видя такое в коде начинает хватать кондратий
        Есть такое. От срани с копипастом ItemsDrop[i][j] и AllMobItemsDrop[j] в каждой строке точно кондратий хватит.
        Ответить
      • >Зачем додумывать вот это "если"
        Когда исходных данных не хватает - другого не остается.
        Ответить
      • > Никто не пробовал посчитать тики процессора?
        Тики процессора сейчас неудобно считать, если это конечно не какой-нибудь атмеловский 8-битный контроллер. За счет спекулятивного исполнения и кешей все эти тики превращаются в ничего не значащее говно. Настоящее время исполнения можно оценить только досконально зная архитектуру конкретного проца (никто этого делать не будет, ибо долго и дорого), или прогнав прогу под профайлером.

        Ну а вообще - спички-спичечки. Сделаем говно в архитектуре (типа необходимости частой очистки вон того массива 600х40), а потом будем выдрачивать производительность на спичках...

        P.S. Под профайлером гоняли?
        Ответить
        • P.P.S. Нахуя вообще этот массив занулять, если там есть ArrayMaxItem и AllMobArrayMaxItem? Новый элемент добавите - так и правильные значения присвоятся, не добавите - а не похуй ли что там лежит? Все равно же правильно написанная прога не будет юзать элементы, которые не попали в допустимый диапазон.

          Вывод - ни циклы не мемсет не нужны. Вообще.
          Ответить
    • ItemsDrop[i][j] := (others => 0);
      Ответить
      • А ты знал, что кресты единственные обладатели шаблонов? В аде их нет.
        http://en.wikibooks.org/wiki/Ada_Programming/Generics
        Ответить
        • Это шаблоны, лол
          Ответить
          • >шаблоны
            Совсем окрестился! Забудь эту мерзкую выкресть - "шаблоны".
            Женерики, они же обобщения.
            Ответить
            • Адские шаблоны не совсем являются шаблонами в крестоблядском смысле, а крестоблядские шаблоны не совсем являются шаблонами в адском смысле, все языки разные, так-то.
              Ответить
              • О том тебе гумно и твердил. Потому и называются они по-разному.
                Ответить
                • В разных языках одинаковые термины обозначают разные вещи, но для буквоедов, чтобы не было путаницы предлагаю называть так: в Аде - шаблоны, в крестах - крестошаблоны.
                  Так вот, шаблоны в Аде есть. А крестошаблонов - нет.
                  Ответить
                  • Уже за тебя всё придумали.
                    В Аде Generics - обобщения.
                    В С++ Templates - шаблоны.
                    А так адашаблоны, крестошаблоны, жабошаблоны, шарпошаблоны, хацкишаблоны - воистину КБГМ.
                    Ответить
          • У тебя кресты головного мозга, лол. Тебе уже везде шаблоны чудятся.
            Ответить
            • Очевидно что Тарас принял крестоблядство.
              Просто не признает этого, опасается гонений.
              Ответить
            • Вот, что крест животворящий делает.
              Ответить

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