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

    +1

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    for (conn_vector::iterator i = m_connections.begin(); i != m_connections.end(); ++i) {
        if (*i == conn) {
            m_connections.erase(i);
            toDelete = *i;
            break;
        }
    }

    Да, С++98. Да, в std::find не умеем. Да, сегфолт. Да, моё.

    Запостил: Elvenfighter, 27 Августа 2014

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

    • Поменял на std::set
      Ответить
      • Да, std::set тут лучше.

        А вообще забавно, что у std::vector нет метода "удалить первый такой элемент". Даже в Java есть List.remove(Object).
        Ответить
        • Потому что нинужно.

          Выпиливание элемента из вектора по значению - неээфективная хуйня с O(n), как бы намекающая нам на то, что стоило было юзать std::set/std::multiset.

          А те, кому это реально надо - поюзают std::find+erase (один) или std::remove+erase (все), не обломаются.
          Ответить
          • Вот чего мне реально в stl не хватает - проецирующих итераторов (вроде жабих keySet() и values()). Ну и ranges вместо вездесущих явных пар итераторов смотрелись бы гораздо лучше...
            Ответить
            • Ну проецирующий итератор, имхо, нетрудно замутить - он же точно такой же, как обычный. Только звездочка возвращает не весь pair, а один из ее элементов...

              А вот range мне и самому хочется.
              Ответить
              • > нетрудно замутить
                Да практически все алгоритмы из стандартной библиотеки нетрудно замутить. Но ведь лень.
                Ответить
                • > Да практически все алгоритмы из стандартной библиотеки нетрудно замутить
                  Велосипедостроительная промышленность? Да там ещё и грабли придётся поворошить. И приправить костылями по вкусу
                  Ответить
              • кому хочется range, могут колоться и плакать об буст, там оно есть
                но, если честно, он мне никогда не казался удобным
                Ответить
                • Не, boost.range неудобный. Вместо одной концепции теперь две - итераторы и range из пары итераторов.

                  Кмк, проще упаковать всё в одну сущность - последовательность с функциями empty(), size(), front(), back(), pop_front(), pop_back(), и т.п. (в зависимости от концепции).
                  Да и не было бы проблем с мусором после удаляющих алгоритмов (remove_if, unique и т.п.)
                  // iterators
                  std::find(my_collection.begin(), my_collection.end(), elem) == my_collection.end();
                  
                  std::copy(left_collection.begin() + 5, left_collection.end(), std::back_inserter(right_collection));
                  
                  // sequences
                  std::find(my_collection, elem).empty();
                  
                  std::copy(view(left_collection).pop_front(5), rigth_collection);
                  Ответить
                  • вот почему в std::copy сначала идет исходная коллекция, а не результирующая? Где наследие сишечки memcpy, strcpy и прочее? Да и rvalue/lvalue не спроста ж назвали.
                    Ответить
                    • > Где наследие сишечки
                      Благополучно предано забвению, к счастью. я всегда путался в этих memcpy, мне привычней думать "что копируем - куда копируем".

                      Да и юниксовые соглашения - первым аргументом у команды всегда идёт то, что уже существует.
                      mv source target
                      cp source target
                      ln source target
                      Ответить
                      • Хз. Я пока не понял как в диреде симлинки создавать, у меня всегда получалось только со второго раза.
                        Ответить
                      • ln target link-name
                        Ответить
                        • Суть таже, поменялись лишь названия.
                          Первым аргументом - то, что уже есть, вторым - то, что хотим создать.
                          Ответить
                          • Всех заспорил.

                            >мне привычней думать "что копируем - куда копируем".
                            >юниксовые соглашения - первым аргументом у команды всегда идёт то, что уже существует
                            Однако если рассмотреть запись без сайд-эффектов: dest=copy(src);
                            Ответить
                            • > без сайд-эффектов
                              Т.е. это не грязное присваивание, а таки чистейшее математическое равенство? Тогда с тем же успехом можно писать copy(src) = dest. Ибо равенство коммутативно.
                              Ответить
                              • >Т.е. это не грязное присваивание
                                А если мы декларируем и инициализируем переменную, это тоже считается грязным?
                                >> без сайд-эффектов
                                Я кстати не говорил ни о каком "грязном". Для буквоедов речь шла о неявных сайд-эффектах.
                                Вообще надо смириться с постулатом что в окружающем нас мире нет ничего абсолютно чистого.
                                Ответить
                                • > переменную
                                  Переменная по определению грязна. Она же переменная, а значит ее значение может меняться.
                                  Ответить
                                  • >Она же переменная, а значит ее значение может меняться.
                                    Таки доебался, а. Вот злодей.
                                    Ответить
                            • > dest=copy(src);

                              Хм, если отталкиваться от физических аналогий, то можно рассмотреть процесс переписывания человеком чего-либо в тетрадь.

                              Мне как-то ближе описание "Вот тебе источник, запиши в тетрадь". Может быть, кому-то проще "вот тебе тетрадь, перепиши в неё из источника".
                              Ответить
                              • Я не утверждаю что dest->src способ лучше.
                                Пример с юниксом очень убедителен на самом деле.
                                Почта и циклы, например, тоже используют запись в порядке from-to.
                                Ответить
                          • Кстати, даже в ассемблере слева-направо:
                            mov $42, %eax
                            P.S. А порядок аргументов в strcpy()/memcpy(), возможно, родился из PDP'шного асма...
                            Ответить
                            • > даже в ассемблере слева-направо:
                              Смотря в каком.
                              PS А как записывается FMA?
                              Ответить
                              • vfmaddpd %xmm0, %xmm1, %xmm2, %xmm3
                                vfmadd132pd %ymm0, %ymm1, %ymm2
                                превращаются в
                                vfmaddpd xmm3, xmm2, xmm1, xmm0
                                vfmadd132pd ymm2, ymm1, ymm0
                                Как-то так, если верить gcc и ndisasm. Т.е. тоже в обратном порядке, приёмником справа.
                                Ответить
                              • P.S. Самая жопа в том, что в этом синтаксисе все эти 132, 231 и т.п. надо читать вверх ногами...
                                vfmadd231pd %ymm0,%ymm1, %ymm2
                                vfmadd231pd ymm2,
                                ymm1, 
                                ymm0
                                
                                ymm2 = ymm1 * ymm0 + ymm2
                                Ответить
                                • Бля, зафейлил разметку ;(
                                  Ответить
                                • >>Самая жопа в том, что в этом синтаксисе все эти 132, 231 и т.п. надо читать вверх ногами...
                                  Вот-вот. На первый взгляд логичнее синтаксис:
                                  mov eax,9; eax=9
                                  add eax,9; eax+=9
                                  Однако гас более подходит под предложение типа: "записать 9 в eax". "Добавить 42 к ebx". И в этом есть смысл: мы же вычисляем сначала правую часть, а потом записываем в левую.
                                  А в если операнды в скобках, то мы должны прочитать самое крайнее выражение.
                                  y=f(g(h(i(x)))); 
                                  y= f(
                                      g(
                                          h(
                                              i(x)
                                          )
                                      )
                                  )
                                  Порядок вычислений вынуждает нас читать сверху вниз, или справа налево.
                                  Потому ms в linq ввели сахарок, напоминающий cps.

                                  Наверное говно в присваивании и скобках, логичнее так:
                                  9 → eax
                                  f(x) → y
                                  Ответить
                                  • >вынуждает нас читать сверху вниз
                                    снизу вверх же.
                                    Ответить
    • У меня например есть привычка обходить коллекцию из конца в начало если удаляю элементы попутно, рикаминдую.
      Ответить
      • Готов к школе, рикаминдатор?
        Ответить
      • И в чем же скрытый смысл этого приёма?
        Ответить
        • Скрытого нет. Если идешь вперед и удаляешь элемент, во первых нужно итератор (переменную цикла) двинуть назад (чтобы не перескочить (теперь уже не уверен насчёт итератора)), во вторых граница цикла смещается. Если идешь из конца в начала этого нет.
          Ответить
          • Идею понял. Нинужно. Т.к. std::remove_if() или его наколенный аналог будут эффективней и наглядней.
            Ответить
        • ну дык если прямой обход делать половина элементов останется.
          Ответить
          • > половина элементов останется
            Мда.
            Ответить
            • Пзда

              https://ideone.com/rnd6yV
              Ответить
              • Действительно пзда. Мне, как байтоёбу, стрёмно смотреть на removeAt() из массива list'а в цикле. Ладно бы из связного списка, он такое стерпит. Но тут ты двигаешь хвост массива на каждое удаление. И выходит O(n * m), где n - сколько было, m - сколько удаляем.

                А крестоблядские std::remove() и std::remove_if() удаляют любое количество элементов за O(n).
                Ответить
                • ну ты спрашивал почему он обходит с хвоста. видимо потому что когда пробует с головы - не выходит

                  Ну и естественно это синтетический пример, я еще не настолько ебанутый что бы так чистить листы

                  Алсо видел говнопример

                  - очистите лист

                  решение

                  list = new List<SomeShittyType>(list.Count);
                  Ответить
              • Примерно вот так оно устроено: https://ideone.com/pe858m
                Ответить
                • я тут так же где то писал, правда давно и пруфы утеряны
                  Ответить
        • Приём - говно.

          В STL метод erase контейнеров как правило возвращает итератор на следующий итератор. Поэтому можно обойти и очистить контейнер в одном прямом цикле.
          for (auto i = c.begin(); i != c.end();) {
              if (!is_good(*i)) {
                  i = c.erase(i);
              } else {
                  process(*i);
                  ++i;
              }
          }
          Буквально вчера юзал такой приём.
          Ответить
          • Для векторов будет квадратная питушня.
            Ответить
            • Ну так не надо его с векторами юзать, голову выключать вообще вредно. В моём случае это хэш-табличка.
              Ответить

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