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

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    auto getMaxSize = [](const auto &vec) {
        if (vec.size() == 0)
            return 0;
        const auto &max = *std::max_element(
                    vec.begin(),
                    vec.end(),
                    [](const auto &lhs, const auto &rhs){
            return lhs.size() < rhs.size();
        });
        return max.size();
    };

    Раньше я не понимал актуальность шутки:
    In C++14, you just write auto auto(auto auto) { auto; } The compiler infers the rest from context

    Запостил: Antervis, 23 Июня 2016

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

    • Уж const то точно никуда не денется. Будет auto const auto(const auto &auto) {const auto & auto; }
      Ответить
    • вы все еще делаете `vec.size() == 0`? тогда мы идем к вам!
      Ответить
      • Куда веселее list.size() == 0 до С++11
        Ответить
        • после кошмаров с С++99, честно говоря я даже у вектора .empty() вызываю. а вдруг.

          с другой стороны, для меня как раз это всегда и было показательным примером того что С++ компилятор "не понимает" С++: `.size() == 0` это очевидно `.empty()` но соптимизировать это компилер просто в принципе не способен.

          ЗЫ тут еще давеча пытался асфильтировать граблевое поле std::sort() vs .sort(). тоже не приятно. у листа есть .sort(), а вектор надо std::sort(). специализации std::sort() для листа - нет. `std::sort( container )` тоже нет. просто мля сказка: в одном месте поменял vector на list - и я уже не помню сколько мегов/гигов был лог ошибок билда.
          Ответить
          • > но соптимизировать это компилер просто в принципе не способен.

            ... а что если попробовать питоновый вариант? .size() возвращает класс, в котором перекрыты операции сравнения? там же понадобится и оператор конверсии в число. вопрос у чего будет приоритет: операторов сравнения или оператора конверсии.
            Ответить
          • а разве empty() это не инлайн-версия size() == 0?
            Ответить
            • для вектора - да. остальные контейнеры - сомневаюсь что даже на С++11 это сильно меняли.

              в С++99 контейнеры не кэшировали колво элементов, почему вызов .size() для дерева или связного списка был тупым проходом по структуре. а .empty() это всего лишь проверка есть ли вообще элементы. в дереве - root == NULL, в связном списке - head == NULL.
              Ответить
              • а, ну тут вектора
                Ответить
              • https://godbolt.org/g/fFU9mT

                Бля, он переполнение что ли ожидает и из-за этого боится выбрасывать цикл?
                Ответить
                • https://godbolt.org/g/ObhHdn

                  Сайзтэбляди соснули! Вот что UB животворящий делает!
                  Ответить
                  • даже не смешно.

                    ЗЫ не только переполнение - вечный цикл так же возможен.

                    ЗЗЫ переключился на icc - тот генерит цикл в обоих случаях.
                    Ответить
                    • Ну вот с int'ом (который нельзя переполнять) gcc всё-таки почуял свободу и выкинул злоебучий цикл...
                      Ответить
                      • >который нельзя переполнять

                        што
                        Ответить
                        • Переполнение int — UB. Если оно происходит, компилятор имеет право вызвать Чёрного Властелина тебе на дом. Или сделать что-нибудь ещё менее приятное.
                          Например:
                          for( int i = 0; i < i + 1; ++i)
                              vec.push_back(i);

                          Так как инт переполняться не может, условие всегда положительное, то есть цикл эквивалентен
                          int i = 0;
                          while(true)
                              vec.push_back(i++);

                          Так как бесконечные циклы — UB, компилятор имеет право выкинуть его нахуй.

                          В результате вместо вектора наполненного числами [0, INT_MAX), можно получить bad_alloc, либо нихуя. А также ещё пару сотен весёлых случаев.
                          Ответить
                          • В общем, если есть код, в котором при наступлении определённых условий происходит UB, компилятор обычно генерирует и оптимизирует код исходя из предположения, что эти условия никогда не наступят.

                            К примеру с size_t, переполнение беззнаковых отлично определено. И size() == 0 может быть true в двух случаях: если сравнение провалилось в первый же раз, или если нод настолько много, что size_t переполнилось (возможно неоднократно) и вернулось к 0. Поэтому компилятор не выкидывает цикл.

                            В случае с int, вариант всего один: если первое сравнение провалилось. Так как большинство компьютеров использует дополнительный код, то физически переменная может переполнится и дойти опять до нуля, но с точки зрения языка, это произойдёт только в случае наступления UB, а компилятор имеет право такие случаи игнорировать.
                            Ответить
                    • > вечный цикл так же возможен
                      https://godbolt.org/g/lAi87k

                      Да, походу он реально пытается не потерять бесконечный цикл.
                      Ответить
                      • И даже -funsafe-loop-optimizations не помогает его убедить...
                        Ответить
                        • godbolt линки сломались, можешь сам попробовать трюк из хез знает какого там мишн критикала: вместо `while(next)` сделать обычный for цикл с фиксированым лимитом типа `for(i=0;i<MAX_ULONG;i++)`. это должно гарантировать что цикл не будет вечным.
                          Ответить
                  • а как этот сервис понимает какой кусок асма показывать?
                    Ответить
                    • Вроде просто все глобальные функции (во всяком случае методы внутри класса не показывал).
                      Ответить
                  • но имхо разработчик сам должен позаботится что empty работает за O(1), а не молиться что божественный O3 всё сделает

                    Тем более size не сохранять это вообще тупо
                    Ответить
      • Да нет же, тут хотят
        template <class Containers> size_t max_size(const Containers& cs) {
            size_t max_size = 0;
            for (const auto& c : cs)
                max_size = std::max(max_size, c.size());
            return max_size;
        }
        Ответить
      • > вы все еще делаете `vec.size() == 0`? тогда мы идем к вам!

        нет, мы делаем vec.size() === 0
        Ответить

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