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

    +14

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    void ThumbnailAdapter::clearCache(size_t index) {
        if ((size_t)-1 == index) {
            mImages.clear();
        } else {
            ImagesMap::iterator it = mImages.find (index);
            if (mImages.end() != it) {
                mImages.erase(it);
            }
        }
    }

    годная очистка map'ы

    Запостил: shomeser, 12 Марта 2013

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

    • что-то не так?
      Ответить
      • Видимо, магический параметр size_t(-1), который означает kill all thumbnails
        Ответить
        • хз, имеет право на жизнь
          как и имеет право erase(iterator) вместо erase(key)
          Ответить
          • >как и имеет право erase(iterator) вместо erase(key)
            зачем? если в ф-ю и так передается ключ?
            Ответить
            • по производительности однохуйственно (не удивлюсь, если erase(key) проиграет)
              но никто не знает, что афтор мог сделать с найденным элементом, подлежащим удалению
              может вызовет it->prepare_to_die_bitch(), а может ничего не сделает
              ценой всего лишь одной лишней строчки

              ну и да, поведение двух удалений в случае, например, multimap будет разным :)
              Ответить
              • >может вызовет
                я исхожу из того, что приведенный гк полный, иначе ожидаю видеть строки:
                //... some code etc

                >например, multimap
                кто ж спорит, но о5 таки, речь тс шла про map, а не о чем-то другом
                Ответить
                • http://liveworkspace.org/code/2vAxRR$1
                  Ответить
                  • Интересный парадокс. А мне всегда казалось, что erase по ключу как раз запилен как find+erase по итератору, и скорости должны быть примерно одинаковыми.
                    Ответить
                    • ну что erase(key) проиграл erase(it) это вполне ожидаемо
                      обычно set, multiset, map, multimap выполняются на одном базовом классе, реализующем rb-tree
                      поэтому size_t erase(key), сделанный в лоб, должен найти пару итераторов - границы где лежат элементы с этим ключом, затем найти distance (надо же вернуть число удаленных) + поудалять всё в этих границах (можно одновременно)
                      но что в 2 раза почти разница - это как раз удивительно, снова привет libstdc++?
                      Ответить
                      • > обычно set, multiset, map, multimap выполняются на одном базовом классе, реализующем rb-tree
                        Ну, в принципе, это объясняет проблему. Причем в libstdc++ походу в конец обленились, и запилили set через multiset, поправив insert'ы и добавив скобки.

                        set<> и map<> же по определению гарантируют, что в них ключ встречается только один раз, есть какая-то адекватная причина, по которой они не стали бы пользоваться этим знанием?
                        Ответить
                        • посмотри дебаггером в какой конкретно метод внутренней реализации попадает в set::erase(key)
                          я на работе мельком студийную реализацию смотрел - там как раз примерно так, как я описал - xtree посрать уникальный или нет реальный контейнер, он ищет пару итераторов как границы
                          Ответить
                  • неправильный тест. у s1 и s2 разные мемори лэйауты на микро-уровне.

                    сравнивать надо удаление из копий s1.

                    http://liveworkspace.org/code/2vAxRR$5

                    последние две строки вывода: разницы в производительности (s3 v. s4) почти нет.
                    Ответить
                    • ну вот, теперь разница ожидаема
                      Ответить
                    • >у s1 и s2 разные мемори лэйауты на микро-уровне.
                      а можно поподробнее?
                      Ответить
                      • s2 более кеш-френдли, т.к. его соседние узлы скорее всего находятся в соседних областях памяти (он наполняется уже удобным для себя способом)
                        у s1 соседние узлы фрагментированны, т.к. он наполнялся рандомно
                        Ответить
                        • ну, т.е. вопрос в реализации копирующего конструктора?
                          Ответить
                          • ну копирующий конструктор по определению не может плохо скопировать
                            ему же исходное дерево надо обойти, каким бы способом он его не обходил, соседние узлы (родственные или сестринские) будут локализованы лучше рандомно аллоцированных
                            Ответить
                            • а если он сделан как-то так?
                              using namespace std;
                              
                              template <class T>
                              set<T> copyset( const set<T>& src )
                              {
                                 set<T> s;
                                 for( T t : src )
                                 {
                                    s.insert(t);
                                 }
                                 
                                 return s;
                              }
                              Ответить
                              • я же написал - каким бы способом ни делал
                                в этом способе каждый родительский элемент будет лежать рядом со своим правым, что уже неплохо
                                http://liveworkspace.org/code/9ZspQ$0
                                Ответить
                                • тьху. наконец-то понял. фишка в том, что перебираются уже сортированные.
                                  Ответить
                        • да. скорее всего именно так.

                          я это первый раз на своих доморощеных AVL деревьях заметил. два теста должны были давать одинаковую (и ассимптотически, и по количеству операций) производительность. но один тест работал стабильно на 10-20% медленее. после длительных разборок, разница свелась к тому в каком порядке элементы встявлялись, опходились.
                          Ответить
    • меня больше всего тут порадовало приведение -1 к size_t
      у нас ещё встречались товарищи, которые -1 возвращали в качестве указателя
      Ответить
      • И даже такое было:
        // функция возвращает NULL при ошибке и не NULL при успехе
        some *func() {
            ...
            return !NULL;
        }
        Ответить
        • даже в c++03 было именно такое - operator void * () const для потока
          чтобы делать while (stream >> item) ..., при этом, не конфликтовало с приведением к int
          в c++11 заменили на explicit operator bool ()
          Ответить
      • > -1 к size_t
        std::string::npos, например
        такое нередко встречается в жизни, когда надо из беззнаковых чисел выбрать специальное
        Ответить
        • Ещё вспоминаются off_t для lseek, ltrunc. А приведение, чтоб ворнингов не было.
          Ответить

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