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

    +160

    1. 1
    2. 2
    3. 3
    4. 4
    uint64_t search(StringList& who, const string& aName, const string& aSize,TypeModes aTypeMode, SizeModes aSizeMode, const string& aToken, const StringList& aExtList, void* aOwner = NULL) 
    {
        return search(who, aName, Util::toInt64(aSize), aTypeMode, aSizeMode, aToken, aExtList,aOwner);
    }

    А теперь небольшой _опрос_ :
    Каково, по вашему мнению, необходимое и достаточное
    качество и количество параметров метода/функции, при котором необходимо(по самым разным причинам) объединять их(параметры) в _меньшее_количество_ , используя встроенные/пользовательские типы данных.
    Например: https://github.com/negativ/eiskaltdcpp/blob/master/dcpp/SearchManager.h

    Запостил: sayidandrtfm, 10 Сентября 2011

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

    • Я думаю, больше четырёх уже не торт.
      Ответить
    • От 3 до 4.
      Ответить
      • Тема уже поднималась. Говорили, что до 7 включительно - это вполне терпимо, если не путаю цифры, конечно.
        Ответить
        • Можно точнее?
          Ответить
          • Увы, тема затерялась где-то здесь, раздел, вроде бы С++ и был.
            Точнее вам скажут авторы своих слов, если наткнутся на этот пост.
            Ответить
        • Нагуглил более менее обобщающую формулировку - «Бессознательные автоматизмы психической деятельности — доминанта внутреннего и видимого извне поведения человека в объективной реальности, что обусловлено возможностями сознания человека в обычном состоянии бодрствования удерживать одновременно не более 7 — 9 объектов или процессов и перерабатывать информацию со скоростью не более 15 — 16 бит в сек.»
          Т.е. нормально 7, максимально 9, больше гении.
          Ответить
          • >не более 7 — 9 объектов или процессов
            5-7
            Ответить
          • >перерабатывать информацию со скоростью не более 15 — 16 бит в сек

            лол, ну это так же тупо, как и сказать, что функция void foo(object* v) перерабатывает 4 байта только потому что на входе даётся один указатель... а то что эта функция в своём теле может перелопачивать терабайты данных -- это как-то пофигу, ага...

            то же самое с человеком, это 15 — 16 бит в сек. -- это только размер ссылок на сложные объекты этого мира. внутри там пипец чо творится же. любой компутер позавидует.
            Ответить
    • Тут вкуснее https://github.com/negativ/eiskaltdcpp/blob/master/dcpp/HttpConnection.cpp
      Ответить
    • Бывают крайне суровые случаи (Groovy):
      http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/main/org/codehaus/groovy/runtime/ArrayUtil.java
      Но там явно имеет место оптимизация размера байткода.
      (кажется, этот код уже когда-то проскакивал на ГК)
      Ответить
    • Источник: http://govnokod.ru/7828
      Ответить
    • 11 параметров терпимо, если они логично упорядочены, например StretchBlt.
      Ответить
    • Не больше 42.
      Ответить
    • сильно зависит от контекста. В среднем 3-4, но иногда и 2 - много.

      лучше логически зависимые параметры объединять в структуры.
      Например, void move(int x,int y) - вполне ничего, но можно и void move(Point point).

      А иногда параметры никак не соотносятся, кроме как отношением "параметры этой функции". В таком случае вполне можно оставить и десяток параметров, но можно и создать специальную структуру "для этого случая".

      Плюсы и минусы двух подходов, думаю, очевидны:
      когда много параметров:
      - запись громоздкая и рассеивающая внимание при заполнении вызова
      + быстрый и экономный вызов
      передача структуры:
      + более понятное API
      + структуру можно использовать повторно
      - фрагментация памяти при выделении и уничтожении краткоживущих объектов, возможны утечки памяти
      - особенно в циклах заметно падение производительности при многократном создании\уничтожении таких структур

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

      Обычно, лучший выбор для хранения в полях - редкоизменяемые значения, для параметров - значения менее предсказуемые.
      согласитесь, пример, переписанный так, глуп:
      this.x=0;
      this.y=0;
      this.move();//внутри используются поля x и y.

      -
      исчерпывающе?
      Ответить
      • Я про с++, если что:
        Ещё + структуры:
        Можно задать конструктор по умолчанию и вообще добавить функций для лёгкой инициализации членов структуры за 1-несколько вызовов.

        >когда много параметров:
        >+ быстрый и экономный вызов
        Быстрее передать одну ссылку на структуру в стеке, чем кучу параметров.
        Ответить
        • >Быстрее передать одну ссылку на структуру в стеке
          Конечно, лучше когда все параметры находятся в классе\структуре, помещенные туда конструктором или конструктором по умолчанию, а ты просто вызываешь одну функцию без лишних параметров.
          Ответить
        • > Можно задать конструктор по умолчанию...
          можно - но обычно нам надо менять все параметры, а тогда проблема рекурсируется.

          > одну ссылку на структуру в стеке
          плюс создание\уничтожение структуры в куче
          Ответить
          • >но обычно нам надо менять все параметры
            Не всегда. Да вы и сами сказали, что иногда можно переиспользовать структуру при повторных вызовах функций. Не знаю как у вас, но у меня часто параметры функции не меняются почти и вынесены в поля класса.

            >плюс создание\уничтожение структуры в куче
            GCпроблема. К С++ это не относится.
            Ответить
            • > Да вы и сами сказали...
              правильно, в одном случае лучше так, в другом - иначе. Как именно - это приходит с опытом )

              > GCпроблема
              т.е. new и delete срабатывают мгновенно?
              Ответить
              • Да. В С++ выделение\освобождение памяти под объект в стеке происходит моментально(не считая редких частных случаев, связанных с виртуальной памятью современных ос). Практически одна комманда ассемблера:
                sub esp, sizeof(TMyStruct);Примерно так.
                Ответить
                • Вроде бы речь про кучу шла, а не про стек.
                  Ответить
                  • Я говорил про стек и много раз это повторил:
                    >Быстрее передать одну ссылку на структуру в стеке
                    >В С++ выделение\освобождение памяти под объект в стеке

                    Если у Java/C# проблемы со стеком из-за боксинга, то это не мои проблемы.
                    Ответить
                    • Тогда мне не очень понятно вот это:
                      >плюс создание\уничтожение структуры в куче
                      >GCпроблема. К С++ это не относится.

                      По-моему, никакого боксинга быть не должно, если передаваемый параметр соответствует типу аргумента.
                      Ответить
                      • >плюс создание\уничтожение структуры в куче
                        Это говорил не я. Тем более это минус.

                        >По-моему, никакого боксинга быть не должно, если передаваемый параметр соответствует типу аргумента.

                        GC не сможет следить за временем жизни переданного параметра, если он создан на стеке. Поэтому созданная на стеке переменная боксируется и дальше жизнью её копии управляет GC.
                        По крайней мере так сделано в C#. Можно ли на стеке создать переменную в Java - не знаю.
                        В C# для этого используется ключевое слово stackalloc. Также на стеке создаются простые типы данных и struct.
                        Ответить
                        • > Можно ли на стеке создать переменную в Java
                          нет. По задумке авторов, программерам нечего заморачиваться такими вещами.

                          т.е. явно указать. Этими вещами заведует JVM по своему усмотрению
                          Ответить
                        • >Поэтому созданная на стеке переменная боксируется и дальше жизнью её копии управляет GC.
                          В каком случае? Например тут никакого боксинга нет:
                          int v = 1;
                          f( v ); // void f( int a );
                          Ответить
                          • её размер укладывается в регистры и мы не требуем изменения значения
                            Ответить
                        • > GC не сможет следить за временем жизни переданного параметра, если он создан на стеке.
                          Да, GC не следит за стековыми переменными/структурами. Зачем? Они удалятся, когда выйдут из области видимости, как и в любом другом языке.

                          > В C# для этого используется ключевое слово stackalloc.
                          stackalloc предназначен для выделения буферов на стеке. Простые переменные и структуры создаются без него.

                          > Также на стеке создаются простые типы данных и struct.
                          Тавтология. В шарпушечке простые типы данных и есть struct.
                          Но если уж на то пошло, они могут создаваться и в куче (когда нужно).

                          Подытоживая: зачем вы берётесь судить о вещах, в которых не разбираетесь?
                          Ответить
                • ага, только вот при использовании умных указателей + исключений, там создаются запутанные карты по правильной размотке стека и вызову нужных деструкторов...
                  Ответить
            • У GC нет таких проблем. Java вот вообще не парится с созданием короткоживущих структур. Если функция использует два поля из структуры, то только два ей и передается, а сама структура даже не создается. CPP по возможностям таких оптимизаций - Govno.
              Ответить
              • >CPP по возможностям таких оптимизаций - Govno.
                Подтверждаю всем своим ником.
                Ответить
              • правда? круто, не знал, что оптимизатор Java настолько продвинутый. :)
                Ответить
              • Откуда такая инфа то?
                Ответить
                • Если не ошибаюсь, впервые услышал отсюда (статья для переубеждения упертых сишников):
                  http://www.ibm.com/developerworks/java/library/j-jtp01274/index.html

                  На тот момент это были планы, но в HotSpot 1.6 это уже точно есть и работает. Вообще, JVM сейчас имеет самый зверский JIT. Можете почитать про него в этом блоге:
                  http://blogs.oracle.com/vmrobot/

                  P.S. Я не фанбой Жабы, но присматриваюсь к ее бэкэнду, разочаровавшись в LLVM.
                  Ответить
                  • Чем LLVM разочаровал? GCC слишком слабый?
                    Ответить
                    • Тем, что использует AST в качестве структуры данных. Из-за этого JITтер у них слишком прожорливый, а оптимизации для него - не в кассу. Так что ищу какой-нибудь другой генератор кода, целиком основанный на байткоде и оптимизациях со скользящим окном.
                      Ответить
                      • А что, разве AST не является наиболее удобным для оптимизации представлением кода?
                        Ответить
                        • Деревья слишком далеки от железа - они для глобальных оптимизаций типа инлайнинга, выделения иммутабельных переменных, поиска альясов. То есть того, чего никогда не происходит в динамических языках. И они слишком медленны в обработке - при проходе по дереву много переходов по указателям и промахов кэша.
                          А на байт-коде микрооптимизации и описываются естественно, и проход по байт-коду значительно быстрее, да и памяти занимается ощутимо меньше.
                          Ответить
                          • А разве далёкость от железа не повышает количество возможностей для оптимизации?
                            Да и байт-код генерировать сложнее, наверное.
                            А тебе это зачем - тоже хочешь писать программы, умеющие на ходу создавать участки кода (разный код для разных вводимых данных) и выполнять их? Да, языков, в которых есть такая возможность, пока нету, увы... Почему-то обошли эту тему.
                            Ответить
                          • По-моему, вы что-то путаете.
                            Практически любой (нормальный) компилятор сначала создаёт AST, а потом уже из этого дерева получается байт-код или машинный код. До железа AST не доходит.
                            Ответить
              • Хуйня всё это, Java редко правильно escape analysis делает в силу множества причин.

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

                Почти у любой java-проги можно использование памяти в два раза урезать, просто введя byvalue-структуры на уровне виртуальной машины.
                Ответить
          • Нафига создавать структуры в куче, все на стеке создают?
            Ответить
      • >вынести большинство параметров в глобальные переменные.
        Вот только этого не надо. :)
        Ответить
        • если есть ООП - конечно, лучше пользоваться им. (Раз уж топик в С++ разделе - это по умолчанию :) )
          а вот если язык процедурен - тоже приходится придумывать подход :)
          Ответить
          • структуры в процедурных языках никто не отменял
            Даже на Си используют семантическую эмуляцию ооп
            Ответить
            • и что бы эта структура была видна во вложенных областях видимости (т.е. в вызываемых функциях) без передачи ее как параметра -- вот что я имел ввиду "глобальные переменные".
              Скажем, если есть понятие "модуля" - тогда переменные уровня модуля :)
              Ответить
              • >и что бы эта структура была видна во вложенных областях видимости (т.е. в вызываемых функциях) без передачи ее как параметра

                Просто передаётся ссылка во вложенные вызовы функций или эти самые вложенные вызываемые функции - методы этой структуры. В чем проблема?
                Ответить
                • очень раздражает, особенно если с каждым вызовом кол-во таких структур растет.
                  Ответить
                  • Больше раздражает, чем наличие 100500 параметров функции?
                    Ответить
                    • Вообщем я понял. Вы ратуете за глобальные переменные модуля?
                      Ответить
        • У функции кроме локальных, бывают еще и свободные переменные... так что, такую проблему можно решить и макросами, которые бы содержали/объявляли свободные переменные, или другими инстументами, позволяющими создавать замыкания, кажется в новом C++ это есть.
          Ответить
      • Вполне. Благодарю.
        Ответить
    • Оценивая с позиции производительности.
      В С++ не уверен, что также, а в дельфи в регистрах передаются 3 первых параметра (которые лезут в регистр), считая указатель this/self: eax, edx, ecx. Все остальные передаются через стек, т.е. имеет смысл делать стековую структуру параметров и передавать указатель на нее. В особых случаях прирост становится заметным.
      Еще в подобных функциях имеет смысл избегать изменения порядка аргументов, т.к. в этом случае придется достать параметры из стека и положить уже в нужном порядке - в случае ДЛЛ никак не оптимизируешь.
      Оценивая с позиции читабельности: 3-5 аргументов будет нормально, больше - ну уже некрасиво.
      Ответить
      • я где-то читал, что передача как можно большего числа аргументов через регистры особо на производительность не влияет (ну, может, пару наносекунд выиграешь)

        ведь один хрен в функции имеются локальные переменные, т.е. тут получается шило на мыло: было 3 аргумента в стеке, и 3 переменных в регистрах, а стало 3 аргумента в регистрах, и 3 переменных в стеке (плюс добавим время на их реанжировку по надобности)
        Ответить

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