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

    +159

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    //Я думал тоже так сделать, но иногда для параметра нужны дополнительные аргументы. Например есть operator()(float, int preciseness). С запятыми такого не сделаешь. Я это применил в своих массивах. Можно написать так:
    Array<int> arr;
    arr.Init(), 5, 7, 65, 99, 267; //Инициализирует массива числами, перечисленными через запятую
    //Кстати, сделал такое добавление в массив:
    arr.Insert(0), 5, 7, 3; //Добавляет числа вначало массива
    arr.Insert($), 888, 25, 76; //Добавляет в конец
    arr.Insert($/2), 65, 23; //В середину
    //Знак доллара сделал для схожести с языком D. Теперь не надо писать arr.length, можно писать $. Вообще, это должно быть медленнее, но компилятор оптимизирует и по тестам получается так же.
    //P. S. В govnokod.ru не заносить.

    http://www.gamedev.ru/code/forum/?id=148200&page=6#m76

    Запостил: CPPGovno, 29 Августа 2011

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

    • > //P. S. В govnokod.ru не заносить.
      Ответить
      • Нарушение авторского права. За CPPGovno уже выехали.
        Ответить
        • просто кто-то кого-то реально задолбал зеркалить с геймдева на говнокод
          Ответить
    • > Теперь не надо писать arr.length, можно писать $.

      Кстати, как он это сделал? Через препроцессор вроде не выйдет.
      Ответить
      • напишем свой препроцессор с блек-джеком и шлюхами
        Ответить
      • This is obvious:
        #define $ arr.length
        xD
        Ответить
        • Скорее есть глобальная переменная, куда заносится "текущий" массив CurrentArray.
          А дальше уж
          #define $ CurrentArray.length
          хD
          Ответить
          • Такая потокобезопасность и реентерабельность, что дух захватывает.
            Ответить
          • > заноситься

            > #define $ CurrentArray.length

            Так это он что, перед каждой работой с массивом меняет этот глобальный указатель? Удобно, безопасно.
            Ответить
            • >> заноситься
              Клеветник.

              >Удобно, безопасно.
              Интересно, а можно сделать без этой дыры в безопасности? Ждём автора, пока отпишется.
              Ответить
              • Писать
                Arr.Insert().($/2)
                Чтобы метод Insert() менял глобальный указатель и указатель на функцию, делающую вставку в массив, а перегруженный оператор () уже вызывал это функцию по указателю для массива из глобального указателя.
                В однопоточной программе работать будет. Только медленно и херово.
                Для многопоточной не знаю, что придумать.
                Ответить
        • И привязаться к одному названию переменной?
          Ответить
        • #define LENGTH(array) BOOST_PP_CAT(array, .length)
          #define $ (LENGTH(arr))
          Ответить
    • Я же просил не заносить!
      Ну ладно уже. Расскажу, как сделал.
      Есть класс ContainerPosition, имеющий 2 переменных. Одна означает абсолютное смещение в массиве, вторая относительное. Здесь UINT_MAX - это конец массива, 0 -начало. Это по сути число с фиксированной точкой от 0 до 1. для класса определена операция деления, которая покомпонентно делит оба данных-члена на число. Статическая функция ContainerPosition::End() возвращает экземпляр класса с относительной позицией UINT_MAX и абсолютной 0. А $ определён так:
      #define $ ContainerPosition::End()
      Класс имеет функцию, позволяющую получить настоящую позицию в массиве. Функция Array::Insert принимает первым аргументом экземпляр ContainerPosition.
      Всё, самое сложное описал, а как сделано преобразование int в ContainerPosition и сложение, думаю сами догадаетесь.
      Ответить
      • > а как сделано преобразование int в ContainerPosition и сложение, думаю сами догадаетесь.

        А ты на этом преобразовании скорость терять не будешь?

        > Статическая функция ContainerPosition::End() возвращает экземпляр класса с относительной позицией UINT_MAX и абсолютной 0. А $ определён так:
        #define $ ContainerPosition::End()

        Нафига статические функции лепить, почему не написать просто
        const ContainerPosition CONTAINER_POSITION_END = {UINT_MAX, 0}
        #define $ CONTAINER_POSITION_END
        Ответить
      • Делай со мной что хочешь, Братец Лис, только, пожалуйста, не бросай меня в этот терновый куст. (c)
        Ответить
      • Короче, я бы написал отдельно Insert() для int и отдельно для ContainerPosition
        Ответить
      • А что, стандартные контейнеры совсем не рулят?
        Ответить
        • Мой быстрее, чем vector на 10% при добавлении в конец, примерно также при добавлении точно в середину, в среднем в 2 раза быстрее при добавлении в случайную позицию и имеет постоянную сложность при добавлении в начало.
          Ответить
          • А со списком (list) сравнивали?
            Почему был выбран именно vector?
            Ответить
          • Связный список добавляет элементы в начало и конец за O(1), а в середину за O(n). С ним тоже сравнивали? Ваша реализация читает элементы быстрее, чем vector?
            Ответить
            • Если отключить проверки на выход за пределы массива, то наверное так же. Сложность O(1).
              Ответить
              • На чём основана ваша реализация?
                Ответить
                • Массив работает так же как и vector, но имеет свободное место и слева, и справа. При добавлении в начало он просто растёт влево. Если свободного места слева нет, он перераспределяется так, чтобы чтобы хватило места для добавления в начало с запасом. То же самое с добавлением в конец. Размер перед массивом и после массива можно задать функцией Resize.
                  Ответить
                  • Поздравляю, Вы сделали еще один vector. Только с запасом. Из-за перераспределения добавление в любое место Вашего поделия имеет сложность O(n), где n - число элементов.
                    Ответить
                    • В смысле сложность не постоянная, а постоянная амортизированная. Перераспределение происходит достаточно редко. Тестировал оба массива в тесте, мой быстрее (проверял в Visual Studio 2010.)
                      Ответить
                      • Вы считаете, что выигрыш в производительности в 10% стоит затрат на реализацию, отладку и тестирование собственного контейнера?
                        Ответить
                        • На 10% при добавлении в конец. Insert в среднем в 2 раза быстрее. В начало добавляет с огромной скоростью, по сравнению с vector. И это только с int. Тестировал оба массива со специальным классом, который выводит на консоль, что выполняется конструктор, конструктор копирования, деструктор и оператор присваивания. vector такого навыводил! При перераспределении массива vector вызывает деструкторы и конструкторы копирования. В моём массиве лишние конструкторы и деструкторы не вызываются.
                          Но есть один недостаток: если объекты полагаются на то, что их указатель this остаётся неизменным (например, хранит указатель на себя в отдельной переменной и на свои данные-члены), то будут проблемы. Хотя это может быть преимуществом - меньше возможностей наговнокодить.
                          Ответить
                          • > Но есть один недостаток: если объекты полагаются на то, что их указатель this остаётся неизменным (например, хранит указатель на себя в отдельной переменной и на свои данные-члены), то будут проблемы.

                            Перемещай объекты не мовом, а специальным конструктором сдвига. В С++ надо будет для всех типов писать этот конструктор, а в С++0х это поддерживается на уровне языка, и для типов, для которых нету конструктора сдвига, вызовется побайтовый сдвиг.
                            Ответить
                            • Кажется я понял куда убегал на месяц Тарас - учитьсо
                              Ответить
                            • >для которых нету конструктора сдвига, вызовется побайтовый сдвиг.

                              У вас уже понейронный сдвиг начался.
                              Ответить
                            • я радовался радовался, но вот после этого поста я расстроен.
                              почитай внимательнее что такое move semantic ибо оно имеет крайне малое отношение с понятию move - "двигать" оно больше относится к "перемещать"
                              Ответить
                              • A(A&&) - это как называется?
                                Ответить
                                • move конструктор, но ты говорил о сдвиге вот так
                                  > вызовется побайтовый сдвиг.
                                  разница между
                                  A(A&&) и A(const A& ) есть только в том случае если A владеет указателями на внешние данные
                                  тогда в move конструкторе их можно просто передать новому классу без копирования.
                                  но допустим для Vector3D(Vector3D&&) и Vector3D(const Vector3D&) разницы не будет.
                                  Ответить
                                  • Правильно, так и gammaker говорит о случае нетривиального объекта, например, наличия умного указателя на внешние данные - чтобы при сдвиге хвоста вектора не вызывать кучу раз освобождение, выделение, копирование указателя.
                                    Vecotr3D - это POD, для него нет смысла писать конструктор сдвига.
                                    Ответить
                                    • ок.
                                      Ответить
                                    • >Vecotr3D - это POD, для него нет смысла писать конструктор сдвига.

                                      Неа. Есть:
                                      vec3d vec3d::operator+(vec3d&);
                                      В этом случае придется делать лишнюю операцию копирования для возвращаемого значения, не зависимо от того, временный объект передали и его можно "портить" или нет. А тем более когда a+b+c+...+z+..., то бесполезных операций копирования становится слишком много.
                                      При этом, если есть перегрузка конструктора для временных объектов, которые можно без последствий портить:
                                      vec3d& vec3d::operator+(vec3d&&);
                                      , то есть возможность не копировать каждый раз возвращаемый объект, а использовать возврат ссылки на уже существующий временный объект RValue, в котором можно без последствий разместить результат работы оператора.
                                      Ответить
                          • осталось придумать где это применять...
                            Ответить
                        • И где-то так двукратного увеличения расхода памяти.

                          Впрочем, 10% разницы при добавлении в конец — это, скорее всего, из-за особенности реализации STL в Visual Studio 2010.
                          Ответить
                          • При нехватке места буфер увеличивается в 1,5 раза, как и у вектора. Поэтому, памяти тратится столько же.
                            Ответить
                            • Значит, перераспределяется чаще.
                              Ответить
                              • Так же. Он оставляет запас только в ту сторону, куда добавляются элементы. То есть, если будешь добавлять только в конец, то в начале пустого места не останется.
                                Ответить
                                • Рад, что я запостил твой код на говнокод?
                                  Ответить
                                  • Вообще-то, я просил этого не делать. Но ты меня заманил на этот сайт. Теперь зависимость появилось, а это плохо. Ты кто вообще на gamedev'е?
                                    Ответить
                                    • Я там не зарегистрирован. Там вроде какой то тест нужно проходить при регистрации. Мне было лень.
                                      Ответить
                                    • Зависимость от говнокода? Что за бред? Как это возможно?
                                      Ответить
                                      • это как от героина, только сильнее
                                        Ответить
                                        • Да ладно... Хоть завтра перестану суда заходить...
                                          Ответить
                                      • А так, что я теперь каждый день захожу сюда и смотрю, что мне написали.
                                        Ответить
                                • Хм… Тогда я не вижу подводных камней с этой стороны, за исключение полной бесполезности. Наиболее популярные операции можно сделать столь же эффективными, дополнительное слово к старым трём возможно вообще попадёт в дыру выравнивания, а дополнительные проверки будут только тогда, когда и так действия дороги и частично скомпенсируется выиграшем.
                                  Ответить
                            • а ты можешь придумать хоть один случай где тебе это может пригодиться? может для случая где это может пригодиться стоило написать особый контейнер, а во всех остальных случаях использовать что-то попроще?
                              обычно STL переписывают для того чтоб получить более простые вещи, ибо STL кишит избыточной универсальностью из-за которой страдает быстродействие.
                              Ответить
                              • Он и универсальнее, и быстрее. От универсальности производительность у меня не страдает. И вообще, мне больше нравится использовать свой массив, названия функций у меня более понятные (может только для меня?).
                                Ответить
                                • я не спорю что свой лучше, нужно ли это добавление в начало? во всех ли случаях нужно.
                                  очень часто вседозволенность порождает говнокод
                                  может в случае потребности добавления в начало лучше подумать над каким нибудь более умным решением?
                                  к стати твой вектор не гарантирует что индекс элемента останется тем же, так как при добавлении в начало уже новый элемент будет иметь индекс 0, и если кто-то сохранил индекс по которому он обращался к старому нулевому элементу, то его ждет эпичный фейл при повторном обращении.
                                  Ответить
                                • «Более понятные названия функций» — несовместимость со стандартными алгоритмами в STL.
                                  Ответить
                  • За счёт чего достигается ускорение добавление элементов в середину? Двигать массив всё равно нужно. Выбираете, в какой край лучше подвинуть (влево или вправо), и этим сокращается размер смещаемой памяти?
                    Ответить
                    • Да двигаю в ту сторону, куда ближе. При добавлении точно в середину это не поможет, для этого случая скорость как у vector.
                      Ответить
                  • Одна беда — в начало вектора никто не добавляет (если интересует производительность).
                    Ответить
      • Я так понял - в относительную позицию вставляется легко. А если хочу вставить в 100тую позицию?
        Ответить
        • Относительная позиция равна нулю, а смещение равно 100.
          Ответить
      • Insert() тоже static? круто чувак
        Ответить
        • Почему static? Обычный метод класса Array, принимающий позицию и добавляемое значение.
          Ответить
    • По результатам тестов разницы нет никакой. Наверное, компилятор оптимизирует. У меня же всё объявлено как inline.
      >Нафига статические функции лепить, почему не написать просто
      Потому что класс имеет закрытый конструктор, чтобы пользователь не догадался, что здесь отдельный класс. Пусть пользователь массива считает, что $ - это конец массива, который почему-то нельзя сохранить.
      Хотя можно было сделать end статической переменной класса, не помню, почему я так не сделал. По-моему была какая-то причина. Надо перечитать код.
      Ответить
    • А нахуй это надо?
      Ответить
      • Когда я это делал, я был под впечатлением от языка D, на который к сожалению не могу пока перейти по некоторым причинам. Решил реализовать это на C++.
        Ответить
        • К сожалению, перенос в какой-либо язык фич другого языка часто одновременно хреново читается и тормозит.
          Ответить
        • Как я понял интерес был чисто академический. На практике контейнер не будет использоваться?
          Ответить
          • Вы так говорите, как будто академики занимаются только не используемой хуйней.
            Ответить
            • Мсье говорит так, будто не знает, что такое академический интерес.
              Ответить
          • Почему это не будет? Если он намного лучше встроенных контейнеров, то почему бы его нее использовать?
            Ответить
    • tl;dr
      Мсье изобрёл std::deque?
      Ответить
      • еще мсье изобрел operator$()

        верной дорогой идет товарищ!
        Ответить
        • наша говнокдафильная комманда принимает в свои ряды ещё одного настоящего труженика кодатруда
          Ответить
      • Нет, std::deque реализован как массив массивов, а у меня просто массив.
        Ответить
        • >std::deque реализован как массив массивов
          ОЛОЛОНАБАШОРК
          Ответить
          • Что не так? В книге по STL так было написано.
            Ответить
            • Точнее, списка массивов. Короче, мой Array не похож на deque.
              Ответить
        • >std::deque реализован как массив массивов
          http://en.wikipedia.org/wiki/Double-ended_queue#Implementations
          Ответить
    • Что значит отрицательный рейтинг у кода? Не смешно, не говнокод?
      Ответить
      • с гамедева!
        Ответить
      • Это значит, что кто-то поставил минус.
        А почему - хз. Может, его достали говнокоды с ГД.ру.
        Ответить
    • >//P. S. В govnokod.ru не заносить.

      Хорошо, занесем в личное дело.
      Ответить
    • показать все, что скрытоvanished
      Ответить

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