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

    +12

    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
    QVector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    
    // взяли итератор на нулевой элемент вектора v1
    QVector<int>::iterator it = v1.begin();
    
    // замутили копию
    QVector<int> v2 = v1;
    
    v1[1] = 42;
    *it = 5;
    v2[1] = 100500;
    
    // и что же мы получим?
    qDebug() << v1; // QVector(1, 42)
    qDebug() << v2; // QVector(5, 100500)

    Ловим лулзы с implicit sharing'ом.

    Мораль (она описана в доке): нельзя копировать implicit shared контейнер пока живы и используются неконстантные итераторы на его элементы.

    Запостил: bormand, 06 Мая 2014

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

    • Ответить
    • QOvno какое-то
      Ответить
      • Ну вроде как это единственная утечка абстракции в implicit share контейнерах. В остальном они все-таки ведут себя как копии.
        Ответить
        • Как минимум про это я и пытался сказать в соседнем треде. А с многопоточностью проблема итераторов станет ещё хуже.
          Ответить
          • stl-итераторы и многопоточность - вещи вообще не совместимые...
            Ответить
          • Не станет :) Там худшее что случится - нагрузка по копированию ляжет не на тот тред (хотя мне логика "кто портит, тот и платит" по душе), или произойдет лишнее копирование (если два треда одновременно войдут в detach()).

            Все остальные ошибки они и с stl векторами вылезут. Попортил контейнер во время работы итераторов - ССЗБ (ну разве что кроме std::map'а). Дал доступ к одному инстансу контейнера двум потокам - ССЗБ (к разным инстансам с одним shared блоком можно, все будет норм).
            Ответить
        • почему не сделали детач в неконстантном методе?
          Ответить
          • Зачем? Детач делает тот, кому нужно портить объект. Для остальных он вообще иммутабельный (если сдуру не сделать ССЗБ из топика). Если во время работы константных методов и случится detach() в соседнем треде, то никто ничего не заметит, т.к. тот тред замутит себе копию, а к оригиналу притронется только для чтения.
            Ответить
            • > Если во время работы константных методов и случится detach() в соседнем треде, то никто ничего не заметит, т.к. тот тред замутит себе копию, а к оригиналу притронется только для чтения.

              А если в этот момент, когда делается копия в соседнем треде, произойдет запись в оригинал?
              Ответить
              • > А если в этот момент когда делается копия в соседнем треде произойдет запись в оригинал?
                Все будет норм, т.к. счетчик ссылок декрементят после копирования (см. вырезки из кода в соседнем треде). Тот, кто пишет в оригинал замутит себе копию и насрет в нее. А оригинальный блок данных после завершения копирований умрет от одиночества.
                Ответить
                • В случае STL итераторов это не так. А как я и говорил в соседнем треде - не стану я себе отказывать в их использовании.
                  Ответить
                  • Т.е. я правильно понимаю, что ситуация такая?
                    - два треда имели разные инстансы QVector'а с одним shared блоком
                    - первый тред захотел что-то записать в вектор, вошел в detach() и начал копирование
                    - в это время второй тред через STL итератор поменял что-то в оригинале
                    - кровь-кишки-распидорасило

                    Эта проблема, как я уже неоднократно писал в этом треде, возникает только в одном случае - если ты сделал копирование контейнера при живых итераторах. Если же ты сначала расшарил контейнер, а потом получаешь итератор, то begin() сделает detach() и все будет норм.

                    P.S. Вот замутили бы они clone() для твоего случая - и никакой проблемы бы не было.
                    Ответить
                    • > в это время второй тред через STL итератор поменял что-то в оригинале
                      В сраных жабах во всех дефолтных коллекциях (непотокобезопасных) обычно из итератора кидается ConcurentModificationException, не для контроля, а скорее для того чтобы не использовали их там где не следует.
                      Ответить
                  • template <class C> C clone(C c) {
                        c.detach();
                        return c;
                    }
                    
                    QVector<int>::iterator it = v1.begin();
                    
                    QVector<int> v2 = clone(v1);
                    Как-то так, вроде бы... Все красивей, чем коровкина защита: сразу видно, что именно мы хотим сделать.
                    Ответить
    • Засщита:
      QVector<int> v2 = v1;
      COW_guard(v2);

      Я хз. Должно выглядеть как-то так. Это не я писал, но у нас юзается в проекте "операция подергивание или UB". Я как бы хз как правильно.
      Ответить
      • Просто не надо копировать контейнер во время с неконстантным итератором. Вот и все решение.

        До - можно. И после того, как закончишь юзать итератор - можно. Пусть там хоть 10 потоков потом его дрочат, никаких проблем не случится.
        Ответить
        • Ну щас. Ограничивать себя ещё... Уж лучше подергать, чем не пользоваться частью удобного функционала. тем более что последствий вредных у этого не будет никаких.
          Ответить
          • Можешь вызвать неконстантный begin() или data() эффект будет такой же как от вашего коровьего защитника.

            P.S. Там кстати detach() в паблике, просто недокументированный. Это я так, к слову, не надо его юзать.
            Ответить
            • Гыгы. А они уже 2 года так код пишут. Спрошу потом в чем дело. Может боятся, что недокументированный метод пропадет в будущих версиях...
              Ответить
            • > Можешь вызвать неконстантный begin()
              const_cast<QList<int>&>(cc).begin();
              Ответить
    • А что вы еще ожидали? Любой шаринг данных незащищенных лочкой приведет к неконсистентной катастрофе. И вообще считаю итератор одноразовым объектом, который кстати при синхронизации частенько забывают и обходят стороной, хотя если он может мутировать то что обходит, то капец.
      Интересно как будет разрулена сия проблема в TBVector
      Ответить
      • Это все происходило в одном потоке. Да и сам по себе QVector не потокобезопасный, равно как и std::vector и жабьи List'ы.

        > И вообще считаю итератор одноразовым объектом
        +1. С осторожностью поюзал внутри функции и выбросил. Хранить итераторы - ССЗБ (ну разве что они в привате вместе с контейнером).
        Ответить
        • Единственное место где имеет хоть какой-то смысл совместно юзать - assparallel.
          В жабе для этих целей придумали Spliterator.
          http://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html#CONCURRENT
          Хранить же итератор глобально или копировать имхо какое-то безумие.
          Ответить
          • Лениво читать по ссылке про тот язык который нарек говном изначально и у меня нет желания себя переубеждать. Что-там за расщепленный итератор?
            Ответить
            • >по ссылке про тот язык который нарек говном изначально
              Но там не лисп и не кложура.
              Ответить
          • > Хранить же итератор глобально или копировать имхо какое-то безумие.
            Херню сказал. Иногда например нужно вставить рядом с каким-то элементом. По этой причине итератор нужен. Тот же указатель понятное дело не подойдет в таком случае. А каждый раз искать по элементу его положение в коллекции - верх идеотизма
            Ответить
            • cleaned
              Ответить
              • http://goo.gl/tZFKTc
                Ответить
                • Сиськи классные. Я бы их покусал.
                  Ответить
                • cleaned
                  Ответить
                • чорный властелин во все века рулит )
                  Ответить
                • Говнокодик понемногу превращается в имиджборду ^_^.
                  Ответить
                  • Только аттачить нельзя и треды со скучными лесенками.
                    Ответить
                    • Ну можно на клиенте преобразовать - ссылки на рисунки обернуть в <img> и поставить слева от коммента, убрать отступы, отсортировать комменты по дате, и под комментом проставить ссылки на ответы, которые по наведению в попапе покажут сам ответ. И получится говноборда :)
                      Ответить
                      • Засилье неймфагов ещё забыл.
                        Ответить
                        • Засильенеймфагофикс:
                          $('.entry-author').html('Аноним')
                          $('.avatar').attr('src', 'http://govnokod.ru/files/avatars/noavatar_28.png')
                          $('.author').html('Запостил: <strong>Аноним</strong>')
                          Ответить
                          • Ха-ха-ха, заебца. Теперь осталось только авы убрать (подойдет хуец).
                            Ответить
                            • Уже убрал :) И заодно автора треда выпилил.
                              Ответить
                          • Не работает при развороте коментов из аякса. И при посте тоже.
                            Ответить
                            • > Не работает при развороте коментов из аякса. И при посте тоже.
                              Я знаю. Но я не силен в юзерскриптах. А без них такое особого смысла нету писать, т.к. лень тыкать каждый раз в букмарклет.
                              Ответить
                              • Кто-то писал код обработки такого события в одном из скриптов, можно содрать.
                                Ответить
                                • Завтра поставлю гризманки да перепилю гк в анонимный говнач. Линейный вид, отсортированный по дате, оказался удобней дерева - сразу видать новые комменты.
                                  Ответить
                                  • >говнач
                                    http://shitstream.ru/
                                    Ответить
                                  • И ссылку на предка и детей, как на двачах, сделайте.
                                    Ответить
                                    • Примерно так получилось: http://rghost.ru/55048649.view

                                      Еще с аяксом разобраться, да с закрытием плашек по отведению мыши, и можно альфатестить.
                                      Ответить
                                      • Вот что значит "нечего делать".
                                        Респект таким парнямА у меня что-то апатия какая-то образовалась, даже кодить лень.
                                        Ответить
                                      • > с закрытием плашек по отведению мыши
                                        Глянь на двачах же.
                                        Ответить
                                        • Там много букв в скриптах ;) Да уже вроде бы все доделал... Сейчас еще отправку комментов пару раз проверю, да пойду на гитхаб выкладывать.
                                          Ответить
                                          • Там ещё это связано с загрузкой незагруженного, минимизацией-максимизацией картинок, ... Плюс свой набор функций для работы с DOM.
                                            Я, когда GK parent comment изменял, решил посмотреть, но в итоге сделал просто удаление всплывающего комментария через N миллисекунд, отмену удаления, если мышь перешла на комментарий, удаление через N миллисекунд, если мышь ушла.
                                            Ответить
                                            • А я сделал так - при наведении на линк всплывает попап. При наведении на попап или линк их айдишка сохраняется в переменную. При уходе мышки с линка или попапа в эту переменную помещается нулл и запускается таймер на 200мс. По таймеру удаляются все попапы, лежащие выше того, который был в переменной (или вообще все, если там null). По ощущениям вроде бы похоже на вакабу. Только там таймауты походу больше.
                                              Ответить
                                              • > По таймеру удаляются все попапы, лежащие выше того, который был в переменной (или вообще все, если там null).
                                                Вот эта логика меня затралела, поскольку я не сидел и не сижу на имиджбордах.
                                                Ответить
                          • Древесностружечный фикс:
                            function date_of_comment(c) { return $(c).find(".published").attr("title"); }
                            $(".hcomment").detach().sort(function(a, b) {return date_of_comment(a) > date_of_comment(b)}).appendTo($(".entry-comments ul"))
                            P.S. Является говном, т.к. задваивает комменты при повторном запуске.
                            Ответить
                          • GK 2.0 будет целиком на клиенте?
                            Ответить
                            • Да. У каждого будет локальный ГК, где он будет писать "лакни мои яйца", а в ответ будет автоматически появляться сообщение "въебал минус".
                              Ответить
                              • > локальный ГК, где он будет писать "лакни мои яйца", а в ответ будет автоматически появляться сообщение "въебал минус"
                                Почему не "въебал плюс"?
                                Ответить
                                • > Почему не "въебал плюс"?
                                  Вероятно, тут это чаще пишут.
                                  А вообще, должен же быть какой-то враг/оппонент, с которым надо спорить, ради утопления которого писать боты, фильтровать его юзерскриптами и т.д.
                                  Ответить
                                  • > А вообще, должен же быть какой-то враг/оппонент, с которым надо спорить, ради утопления которого писать боты, фильтровать его юзерскриптами и т.д.
                                    Бой с тенью.
                                    Ответить
                          • Тест.
                            Ответить
                            • Сраная обезьяна не показывает логи во время работы юзерскрипта. Кто-нибудь в курсе, их можно включить?
                              Ответить
                              • А если пойти в хром с tampermonkey?
                                Там console.log вроде бы отображается
                                Только вот при ошибке вываливается текст всего скрипта и текст ошибки :(
                                Ответить
                              • console.log работает. А вообще, вали в хром + tampermonkey, там скрипты можно отлаживать.
                                Ответить
                                • > console.log работает.
                                  Им и дебажился.

                                  > А вообще, вали в хром + tampermonkey, там скрипты можно отлаживать.
                                  Там прям нормальный отладчик, такой же как для остального жс?
                                  Ответить
                                  • > console.log
                                    > дебажился.
                                    Лол

                                    Прям нормальный.
                                    Ответить
                          • Последний тест (наверное)
                            Ответить
            • > Иногда например нужно вставить рядом с каким-то элементом.
              Это когда? И зачем? Лично я стараюсь практически никогда не мутировать коллекцию итератором. Единожды написал такое, и то была говнооптимизация и хак, которого можно было избежать.
              Ответить
            • Удалено модератором. Ханжей здесь не любят.
              Если Вас что-то не устраивает - покиньте сайт.
              Ответить
            • > Тот же указатель понятное дело не подойдет в таком случае.
              Да итератор это и есть указатель, просто обобщенный на случай непотребщины, в которой элементы лежат не подряд единым блоком. Практически все проблемы указателей автоматом переходят и на итераторы, а на деле еще и новые добавляются.

              И обращаться с ними надо именно так, как ты обращаешься с голыми указателями.

              > Херню сказал.
              Нифига не херню. Такой итератор должен лежать рядом с контейнером, в который он указывает. Причем и то и другое должно лежать в привате, чтобы не дай бог между ними рассинхрон не произошел. А глобальный итератор, ссылающийся в хуй знает куда это риалли безумие.
              Ответить
          • >static final int ORDERED
            Чтоэта?
            Ответить
        • > А глобальный итератор, ссылающийся в хуй знает куда это риалли безумие.
          > Хранить итераторы - ССЗБ (ну разве что они в привате вместе с контейнером)

          За что такая нелюбовь к stl-итераторам? Незаменимая же вещь. Примеры:
          1. LRU-кэш на итераторах std::list
          http://stackoverflow.com/questions/2057424/lru-implementation-in-production-code

          2. У меня в поисковике сортированный список документов представлен парой константных итераторов, указывающих на участок иммутабельного индекса. Пару можно прекрасно сплиттить для параллельной обработки. Хотя с этим также неплохо справляются slice-ы в Go-версии.
          Ответить
          • > За что такая нелюбовь к stl-итераторам?
            Это не не любовь, а осторожность. Я же нигде не писал, что я ими не пользуюсь и другим не советую... Просто они настолько же опасны/безопасны, насколько и самые обычные указатели.

            > 1. LRU-кэш на итераторах std::list
            Ну вот mCacheList и mCacheMap надо засунуть в приват какому-нибудь классу, иначе кто-нибудь обязательно порушит инвариант (тут проблема более общая, без итераторов я бы тоже это сделал).

            > иммутабельного
            Ключевое слово ;) Отдавать куда попало итератор на мутабельную коллекцию я бы не рисковал.
            Ответить
            • > они настолько же опасны/безопасны, насколько и самые обычные указатели
              Just as designed. Итераторы и были спроектированы, чтобы моделировать абстрактный указатель. Даже нотацию сохранили, чтобы их не отличить было. Сишники вон таскают всюду указатели и не жалуются.

              Я не предлагаю совать итераторы во все дыры, особенно с учётом с++11 с его range-based for. Концепция Range мне всегда нравилась больше. Но и итераторы весьма полезны и универсальны.
              Ответить
            • >> итераторов, указывающих на участок иммутабельного индекса
              >Ключевое слово ;)
              Истинно. Выше же писал что итератору в 90% случаев необходимо и достаточно быть read-only. Глобальный итератор мутирующий коллекцию - неиссякаемый источник гейзенбагов.
              При этом ни о каких блокировках на итераторе естественно речи не идёт.
              Ответить
    • Мораль: борманд заебал со своим "C++".
      Ответить

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