Кресты / Говнокод #15932 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  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 bormand, (Updated )

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

    • Если "brutushafens" что-нибудь напишет в этой ветке, тем самым он подтвердит свою пассивную гомосексуальность.
      Ответить
    • Ну вроде как это единственная утечка абстракции в implicit share контейнерах. В остальном они все-таки ведут себя как копии.
      Ответить
      • Как минимум про это я и пытался сказать в соседнем треде. А с многопоточностью проблема итераторов станет ещё хуже.
        Ответить
        • Не станет 🙂 Там худшее что случится - нагрузка по копированию ляжет не на тот тред (хотя мне логика "кто портит, тот и платит" по душе), или произойдет лишнее копирование (если два треда одновременно войдут в 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. С осторожностью поюзал внутри функции и выбросил. Хранить итераторы - ССЗБ (ну разве что они в привате вместе с контейнером).
      Ответить
        • Лениво читать по ссылке про тот язык который нарек говном изначально и у меня нет желания себя переубеждать. Что-там за расщепленный итератор?
          Ответить
          • >по ссылке про тот язык который нарек говном изначально
            Но там не лисп и не кложура.
            Ответить
        • > Хранить же итератор глобально или копировать имхо какое-то безумие.
          Херню сказал. Иногда например нужно вставить рядом с каким-то элементом. По этой причине итератор нужен. Тот же указатель понятное дело не подойдет в таком случае. А каждый раз искать по элементу его положение в коллекции - верх идеотизма
          Ответить
              • Говнокодик понемногу превращается в имиджборду ^_^.
                Ответить
                • Только аттачить нельзя и треды со скучными лесенками.
                  Ответить
                  • Ну можно на клиенте преобразовать - ссылки на рисунки обернуть в <img> и поставить слева от коммента, убрать отступы, отсортировать комменты по дате, и под комментом проставить ссылки на ответы, которые по наведению в попапе покажут сам ответ. И получится говноборда 🙂
                    Ответить
                        • Ха-ха-ха, заебца. Теперь осталось только авы убрать (подойдет хуец).
                          Ответить
                        • Не работает при развороте коментов из аякса. И при посте тоже.
                          Ответить
                          • > Не работает при развороте коментов из аякса. И при посте тоже.
                            Я знаю. Но я не силен в юзерскриптах. А без них такое особого смысла нету писать, т.к. лень тыкать каждый раз в букмарклет.
                            Ответить
                            • Кто-то писал код обработки такого события в одном из скриптов, можно содрать.
                              Ответить
                              • Завтра поставлю гризманки да перепилю гк в анонимный говнач. Линейный вид, отсортированный по дате, оказался удобней дерева - сразу видать новые комменты.
                                Ответить
                                • И ссылку на предка и детей, как на двачах, сделайте.
                                  Ответить
                                    • Вот что значит "нечего делать".
                                      Респект таким парнямА у меня что-то апатия какая-то образовалась, даже кодить лень.
                                      Ответить
                                    • > с закрытием плашек по отведению мыши
                                      Глянь на двачах же.
                                      Ответить
                                      • Там много букв в скриптах 😉 Да уже вроде бы все доделал... Сейчас еще отправку комментов пару раз проверю, да пойду на гитхаб выкладывать.
                                        Ответить
                                        • Там ещё это связано с загрузкой незагруженного, минимизацией-максимизацией картинок, ... Плюс свой набор функций для работы с 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. Является говном, т.к. задваивает комменты при повторном запуске.
                          Ответить
                          • Да. У каждого будет локальный ГК, где он будет писать "лакни мои яйца", а в ответ будет автоматически появляться сообщение "въебал минус".
                            Ответить
                            • > локальный ГК, где он будет писать "лакни мои яйца", а в ответ будет автоматически появляться сообщение "въебал минус"
                              Почему не "въебал плюс"?
                              Ответить
                              • > Почему не "въебал плюс"?
                                Вероятно, тут это чаще пишут.
                                А вообще, должен же быть какой-то враг/оппонент, с которым надо спорить, ради утопления которого писать боты, фильтровать его юзерскриптами и т.д.
                                Ответить
                                • > А вообще, должен же быть какой-то враг/оппонент, с которым надо спорить, ради утопления которого писать боты, фильтровать его юзерскриптами и т.д.
                                  Бой с тенью.
                                  Ответить
                          • Сраная обезьяна не показывает логи во время работы юзерскрипта. Кто-нибудь в курсе, их можно включить?
                            Ответить
                            • А если пойти в хром с tampermonkey?
                              Там console.log вроде бы отображается
                              Только вот при ошибке вываливается текст всего скрипта и текст ошибки 🙁
                              Ответить
                            • console.log работает. А вообще, вали в хром + tampermonkey, там скрипты можно отлаживать.
                              Ответить
                              • > console.log работает.
                                Им и дебажился.

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

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

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

        За что такая нелюбовь к 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++, guest?!

    А не использовать ли нам bbcode?


    8