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

    +1

    1. 1
    std::ranges::for_each(tasks, [](auto x) {x();});

    а ещё теперь не нужно писать std::begin(), std::end().
    c++ будущего.

    Запостил: digitalEugene, 10 Мая 2021

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

    • Почему бы не просто for (auto& task : tasks) task()? Работает уже лет 10 и рейнджи не требует.
      Ответить
      • Недостаточно модерново. Если твой код собирается чем-то помимо последнего стандарта — ты ретроград, не успевающий за прогрессом.
        Ответить
      • Цикл = императивность, процедурность, старость, плесень, смерть
        Foreach = декларативность, функциональность, молодость, стиль
        Ответить
    • Зачем придумали ranges, а не ещё одну перегрузку, которая умеет брать begin, end?
      Ответить
      • ranges разрабатываются для решения оснявной проблемы begin и end — нявозможности чейнинга итерирующих функций. Классические ФП-like цепочки, вроде "collection.filter {it % 2 == 0}.map {it * 2}.take(5)", ня крестовых итераторах принципиально нявозможно няписать, не изобретая ленивых генераторов (то есть половины ranges).
        Ответить
        • можно сделать как в питоноячьем говне через функцию, котоаря принимает итератор и лямбду или указатель на фукнцию

          но ленивости (генеаторов) всё равно не будет из коробки, угу
          Ответить
          • Чейнинга всё равно так просто ня получится. А если получится — у тебя уже будет криво и косо реализована половина ranges-v3.
            Ответить
            • угу, но его и в питоне нет, к сожалению.

              можно как-бы сделать (псевдокод)
              take_first(10, sort(&sorter, petuhi.begin(), petuhi.end()))

              будет как питон с его map и прочим itertools

              но в питоне есть генераторы, а тут нету, и если питухов 100000 то багор
              Ответить
              • ФП в Питоне — отвратительное фу, ня него равняться ня нужно.

                > take_first(10, sort(&sorter, petuhi.begin(), petuhi.end()))
                Только тут же возникает проблема: что возвращает sort() и что принимает take_first()? В итераторном коде сигнятура take_first() выглядела бы примерня как "(void) take_first(size_t count, It begin, It end, OutIt outBegin)", и в неё sort() някак ня впихнуть.

                А вот благодаря миксиняшкам такие проблемы решаются тривиальня.
                Ответить
                • принимала бы она коллекцию, и получала от нее begin

                  но это всё не лениво, а значит весьма сомнительно
                  Ответить
                  • > принимала бы она коллекцию, и получала от нее begin
                    Так вот имення чтобы ня принимать коллекцию и делались итераторы. Чтобы ты мог, няпример, легко и просто отсортировать половину коллекции: "std::sort(collection.begin() + collection.size() / 2, collection.end())".

                    А ещё так нячинают возникать проблемы: а что, если я хочу получить из sort() ня vector, а, няпример, list? А что делать с кастомными аллокаторами? А что, если я хочу в take_first засунуть map, а получить vector? И так далее.
                    Вот чтобы таких проблем ня было — и придумали итераторы. Ты сам создаёшь контейнеры, которые тебе нужны, а функции оперируют только няд итераторами. Но, как показала практика, это была далеко ня самая лучшая идея.
                    Ответить
                    • почему не лучшая?

                      имхо, итератор это хорошо, просто небыло красивых средств для ленивости, и потому половина функционала была недоступна..

                      а вот твой пример с /2 отлично работал же, да и независящие от контейнера алгоритмы -- тоже
                      Ответить
                      • 1. Отсутствие ленивости. Как результат — в любой цепочке длиннее одного действия няобходимость ломать мозги над тем, как бы все вычисления провести in-place.
                        2. Отсутствие чейнинга. Тут всё и так понятно: вместо няшного sort().filter().map().reduce() приходится писать гигантские вербозные портянки.
                        3. Няобходимость в std::(back_|front_)?inserter для вставки результата в изнячальня пустой/маленький контейнер.
                        4. Общая высокая вербозность, особення в базовых (в том числе и самых распространённых) случаях. Вместо collection.sort() / sort(collection) — sort(collection.begin(), collection.end()).
                        Ответить
                        • > вербозность

                          Особенно сраная пара remove/erase, про которую так любят спрашивать на собеседованиях.
                          Ответить
                          • О, точня, это вообще бомба.
                            Ответить
                          • А это уже ваша плата за знание устройств коллекций и того факта, что вектор и лист устроены по разному

                            один питух двигает говно, а второй чистит вилкой освободивщееся место если я верно помню
                            Ответить
                            • Только для листа remove из алгоритмов применять не рекомендуется. У него есть свой, особенный remove/remove_if, который делает тоже, что и пара remove-erase для остальных контейнеров.

                              К — Консистентность.
                              Ответить
                        • >Отсутствие ленивости.
                          да, это отсос. В руби я могу сделать цепочку от 0 до бесконечности, и выбрать из нее по условию первые N элементов, а тут фиг

                          >Отсутствие чейнинга.
                          угу( ну вот это как раз как в питоне тоже, и это плохо. А вот в руби... ну ты понял)

                          > std::(back_|front_)?inserter
                          А иначе как контейнер расширится?

                          Итератор в векторе или массиве же это просто указатель на элемент ЗА хвостом, верно?

                          Как же можно сделать так, чтобы при писании туда вектор бы расширялся?

                          >Общая высокая вербозность
                          Угу(( но без итераторов было бы еще вербознее
                          Ответить
                          • > А иначе как контейнер расширится

                            Ну вот поэтому range -- это более красивая концепция чем итератор.
                            Ответить
                            • я не спорю, что range это круто

                              но и итератор на момент с03 тже было круто имхо
                              Ответить
                          • > А иначе как контейнер расширится?
                            А в ranges вообще ничего ня надо расширять. После серии преобразований ты получаешь ленивый генератор, который вообще някуда записывать ня надо: ты можешь итерироваться сразу по няму.
                            Но даже если вдруг понядобилось материализовать — ты просто пишешь условный ... | ranges::to<std::vector> и получаешь всё в лучшем виде.
                            Ответить
                      • > независящие от контейнера алгоритмы

                        Да это миф, на самом деле. Я вот сходу даже не назову алгоритм, который ну совсем прям на любом контейнере работает.

                        Везде или какие-то подвохи с вычислительной сложностью std::find(map.begin(), map.end(), x) vs map.find(x) или какой-то постпроцессинг в духе v.erase(std::remove(v.begin(), v.end(), x), v.end()) нужен.
                        Ответить
                        • > ну совсем прям на любом контейнере работает

                          Ну, они обычно РАБОТАЮТ. Стоит ли так работать, или нет — это другой вопрос.
                          Ответить
                        • алгоритм итерируется по контейнеру и выводит его значения. Он более ли менее годно работает на всех контейнерах

                          просто итераторов бывает много разных: кто-то поддерживает арифметику, кто-то поддерживает запись, итд
                          Ответить
                          • > на всех* контейнерах

                            * На всех кастомных контейнерах, которые косплеят соответствующий стандартный.

                            А поскольку в стандартной либе все контейнеры разные, каких-то общих алгоритмов у них очень мало получается. По сути каждый алгоритм под что-то конкретное нужен. И во многих местах вместо них надо брать кастомную версию из самого класса и т.п. Консистентность на высоте.

                            Короче не особо взлетела эта идея, имхо.
                            Ответить
                            • ну блин, чудес не бывает: никто не обещал вроде что ВСЕ алгоритмы будут подходить ко ВСЕМ контейнерам

                              Это был бы булщит уровня "локальный вызов заменим удаленным вызовом по HTTP, а алгоритм останется тем же" (над этим еще Фаулер ржал в 2003-м), но какие-то алгоритмы всё таки можно переиспользовать
                              Ответить
                              • > но какие-то алгоритмы всё таки можно переиспользовать

                                А какие? Ну вот банальный find. Он работает, по сути, только на листе и не отсортированном векторе. Для мапы/хешмапы надо брать их реализацию, которая за логарифм ищет. А для отсортированного вектора есть binary_search, который на отсортированном листе бесполезен.

                                Так и живём.
                                Ответить
                                • блин, ну вот у меня есть forward iterator который умеет ++ и разыменовываться, так?

                                  Я пишу алгоритм, который итерируется по нему и выводит значение если оно полдходит по условию. Что не так?


                                  Про find: с этим даже джависты отсосали: там вроде поиск в массиве работает только если он сортирован, именно ради бинари сёч

                                  но если мне похуй на перфоманс, я могу написать поиск за O(N) и он будет работать на чем угодно, не?
                                  Ответить
                                  • > но если мне няк на перфоманс, я могу написать поиск за O(N) и он будет работать на чем угодно, не?
                                    Но тогда теряется смысл в специализированных контейнерах. С тем же успехом можня хранить всё в std::vector.
                                    Ответить
                                    • >но тогда проёбывается смысл в специ

                                      А вдруг я ищу что-то в алгоритме раз в 10 лет, а всталяю в середину каждые 1ms, и тогда мне важно взять именно list?
                                      Ответить
                                  • > который итерируется по нему и выводит значение

                                    Ну ок, transform/copy действительно для всех контейнеров работают (на входе). Целых джва алгоритма уже нашли!
                                    Ответить
                                    • all/any/none_of
                                      форич/_н
                                      count/count_if
                                      mismatch
                                      adjacent_find
                                      search/_n
                                      Все что требует не лучше ForwardIterator
                                      Ответить
                                      • > search

                                        search (не путать с find!) на мапе или хешмапе очень полезен, конечно... Хотя иногда что-то и найдёт, наверное.
                                        Ответить
                                        • На хешмапе найдёт только случайно, согласен, а на мапе/сете будет работать, если рассматривать его не как ассоциативный контейнер а отсортированную последовательность. И искать не просто совпадающую последовательность (это делается upper/lower_bound), а какую-то эзотерическую хуйню при при помощи предиката.
                                          Ответить
                                      • > count
                                        std::multimap<std::string, std::string, std::less<>> a{ {"hello", "world"}, { "hello", "you" } };
                                        size_t hello_count = std::count(a.begin(), a.end(), "hello");

                                        (╥﹏╥)
                                        Ответить
                                        • std::vector<std::pair<std::string, std::string>> foo a{ {"hello", "world"}, { "hello", "you" } };
                                          size_t hello_count = std::count(a.begin(), a.end(), "hello");

                                          (╥﹏╥)

                                          Действительно плохой алгоритм.
                                          Ответить
                                          • std::multimap<std::string, std::string, std::less<>> a{ {"hello", "world"}, { "hello", "you" } };
                                            size_t hello_count = a.count("hello");

                                            Это просто ещё один пример потёкшей абстракции.
                                            Ответить
                                    • Так а что ты предлагаешь всё таки?

                                      Спрятать алгоритмы в сами контейнеры, потому что независящий от контейнера алгоритм часто просто не написать?


                                      А мне вот нравится, что у вектора и умассива общие алгоритмы, а в джаве -- нет..
                                      Ответить
                                      • Просветлённые джависты обычно стримы используют, см. ссылку ниже.
                                        Ответить
                                • > А какие? Ну вот банальный find. Он работает, по сути, только на листе и не отсортированном векторе.

                                  А вот взять например метод sort, который есть у std::list и у std::forward_list. А у вектора никакого метода sort нет, используйте std::sort.
                                  Зачем? Зачем? std::sort требует random access iterator и поэтому для std::list и std::forward_list нельзя std::sort, а для std::vector можно? А почему тогда не сделать так, чтоб и у std::vector был метод sort, ну, типа для единообразия?
                                  Ответить
                                  • Вообще контейнеры в крестах какое-то говно. Вот взять опять-таки std::forward_list (в простонародье известен как "односвязный список"), в нем нет метода push_back. Почему? Ответ вероятно будет "потому что это сложно, надо прошагать в самый хвост односвязного списка и потом вставить, это оооочень долго". Эмм, ну допустим, а с хренов каких у std::vector есть метод insert? Ведь следуя такой логике, никакого insert там быть не должно, insert в начало длинного вектора это охренеть как долго. И да, у std::vector есть insert, но нет метода push_front. Где логика? Кто и на каком основании так это спроектировал?
                                    Ответить
                                    • http://stolyarov.info/books/programming_intro/about.html

                                      > Учителям такой категории вообще, судя по всему, всё до лампочки: в C++ используется библиотека STL, а значит, надо рассказать ученикам STL; разумеется, дальше vector'а и list'а обучение никогда не заходит (при этом эти два контейнера, пожалуй, самые бесполезные из всего STL), но самое интересное, что ученики, разумеется, так и не понимают, о чём идёт речь. В самом деле, как можно объяснить разницу между vector и list человеку, который никогда в жизни не видел ни динамических массивов, ни списков и вообще не понимает, что такое указатель? Для такого ученика list отличается от vector тем, что в нём нет удобной операции индексирования (почему её там нет? ну, нам что-то объясняли, но я ничего не понял), так что вообще-то всегда надо использовать vector, ведь он гораздо удобнее. Что? Добавление в начало и в середину? Так оно и для вектора есть, какие проблемы. Ну да, нам говорили, что это «неэффективно», но ведь работает же! Переучить такого ученика практически нереально: попытки заставить его создать односвязный список вручную обречены на провал, ведь есть же list, а тут столько ненужного геморроя! Собственно говоря, всё: если нашему обучаемому дали в руки STL раньше, чем он освоил динамические структуры данных, то знать он их уже не будет никогда; путь в серьёзное программирование ему, таким образом, закрыт.
                                      Ответить
                                      • Учить нячиняющих программистов C++ — крайне тупая идея. Кресты слишком далеко ушли от железа, чтобы студенты няучились понимать низкоуровневые абстракции (в том числе и указатели), но при этом они слишком ужасны, чтобы ня них можня было показывать высокоуровнявые концепции (от алгоритмов и до паттернов).
                                        Имення поэтому учить программированию нядо с C.
                                        Ответить
                                        • ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня ня
                                          Ответить
                                        • Или с «Nim», там есть как высокоуровневые абстракции, так и адресная арифметика. А может быть и нету, на самом деле я ещё ня выучив «Nim», мяу uwu
                                          Ответить
                                        • плюсану

                                          хуже только сразу учить их на каком-нить питоне или JS.

                                          В случае крестов они хотябы будут знать, что бывают массивы, а бываюи сваязанные списки

                                          В случае питона они не будут знать ничево, и не отличать объект от указателя
                                          Ответить
                                          • А в случае с PHP у них будет всего одна структура данных. И им будет её достаточно.

                                            Именно поэтому я за "РНР".
                                            Ответить
                                            • С PHP программистом потом уже ничего нельзя сделать.
                                              Только выкинуть, и нового родить
                                              Ответить
                                        • поддерживаю
                                          Ответить
                              • Ну т.е. можно было не выёбываться с итераторами и их концептами, а сделать концепты для самих контейнеров, как в жабе. По крайней мере было бы сразу понятно, что для чего применять. А сами итераторы оставить как деталь реализации, которая нужна только разрабу новых контейнеров.
                                Ответить
                                • типа сделать интерфейс collection с реализациями list и vector, и у каждого свой sort?
                                  Ответить
                                  • https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps
                                    Ответить
                          • > ну блин, чудес не бывает: никто не обещал вроде что ВСЕ алгоритмы будут подходить ко ВСЕМ контейнерам

                            Контейнеры-хуёйнеры какие-то блядь. Как всё сложно. Предлагаю кложуру и хэшмап
                            https://youtu.be/b-Eq4YV4uwc?t=1607
                            https://youtu.be/b-Eq4YV4uwc?t=1724
                            Ответить
                            • Программисты ня PHP полностью одобряют!
                              Ответить
                              • Пока крестовики будут подбирать правильную кобенацию из своих конь-тейнеров, скриптушки закодят всё на generic структурах данных и пойдут брать другой заказ.
                                Ответить
                                • Так точня. Поэтому за PHP будущее, а остальные языки, где нядо думать, сгниют!
                                  Ответить
                                  • У меня нет в контроллерах никакого PHP, именно поэтому я за контроллеры. И std::kokokoнтейнеров из крестоговна тоже нет.
                                    Ответить
                                    • > У меня нет в контроллерах никакого PHP
                                      https://www.youtube.com/watch?v=ouUloBNBhOA

                                      > И std::kokoнтейнеров из крестоговна тоже нет.
                                      Тебе ня придётся учить стандартную библиотеку, если каждый раз ты пишешь стандартную библиотеку сам╰(▔∀▔)╯!
                                      Ответить
                                      • > Тебе ня придётся учить стандартную библиотеку, если каждый раз ты пишешь стандартную библиотеку сам

                                        Стандартная библиотека крестоговна мне там банально не подходит т.к. там требуется какой-то хип, а у меня в контроллерах может не быть никакого хипа (если всё решаемо статической памятью), а еще там какие-то исключения RTTI и прочая такая питушня, которая мне в контроллерах няхуй не нужна. Да и в целом можно поднасобрать каких-то реализаций различной питушни на сишечке с гитхаба, и ее использовать вместо крестовой говностдлибы.
                                        Ответить
                                        • > там требуется какой-то хип
                                          Зачем?

                                          > исключения RTTI
                                          -fno-exceptions -fno-rtti

                                          > Да и в целом можно поднасобрать каких-то реализаций различной питушни на сишечке с гитхаба, и ее использовать вместо крестовой говностдлибы.
                                          И собрать свою говнолибу.
                                          Ответить
                                          • > > там требуется какой-то хип
                                            > Зачем?

                                            Память выделять там, например для какой-нибудь там std::list питушни. Без хипа я могу например так сделать: https://govnokod.ru/23275
                                            Ответить
                                            • > так сделать

                                              Ну в бусте вроде были такие контейнеры... И интрузив списки, которые сишники любят делать руками тоже были.

                                              А стд, конечно, очень сильно завязано на хип и исключения. 90% стандартной либы можно тупо выбросить под фристендингом.
                                              Ответить
                                            • Так можня сделать свой собственный аллокатор. Там по сути просто обернуть всю эту алгоритмушню в одну структуру и всё.
                                              Ну а вообще в том посте roman-kashitsyn всё правильня расписал.
                                              Ответить
                                              • > сделать свой собственный аллокатор

                                                А как репортить ошибку, когда в нём место закончилось? Рушить абстракцию и приделывать аллокатору какое-нибудь has_enough_space()?
                                                Ответить
                                                • Как в /23275:
                                                  fprintf(stderr, "ERROR! No empty space!\n");
                                                  exit (-1);
                                                  Ответить
                                                  • > exit (-1);

                                                    Ну заебись для эмбеддеда... На какую-нибудь опциональную хуйню для UI памяти не хватило, весь чип ушёл в ребут.
                                                    Ответить
                                                    • > Ну заебись для эмбеддеда...

                                                      Настоящие цари заранее должны знать, что им там всего хватит под все возможные сценарии. Если вдруг памяти не хватает, это баг, и надо менять структуру или допаивать ОЗУ или менять контроллер
                                                      Ответить
                                                    • Ну так если в микроконтроллере место закончилось — это в любом случае всё, финита ля комедия.

                                                      > Железка может уметь много чего делать, и ей может быть не нужно делать это одновременно (и памяти на одновременное делание всего у нее тоже нет). Поэтому железка может выделять память под някню№1, сделать някню№1, освободить память, выделить память под някню№2, сделать някню№2, освободить память. И эти хуйни№x может быть много, некоторые не сильно жрущие оперативку хуйни могут вполне работать одновременно, и они могут быть заранее неизвестны т.е. загружаться с внешнего флеш-накопителя или по блютузу какому-то скачиваться и устанавливаться, если это какая-то IoT-няшнота. Так что для каких-то задач это вполне себе пригождается.
                                                      https://govnokod.ru/27391#comment625630
                                                      Ответить
                                              • > Так можня сделать свой собственный аллокатор.

                                                А аллокатор может возвращать uint8_t ? Ну типа это память не вообще, а память, выделенная в контексте некоторой арены, где мы адресуемся не по байтикам, а по блокам в 16 байтиков, и этот возвращаемый uint8_t это смещение относительно какого-то там указателя в этой арене, который надо еще на 16 умножить и прибавить к этому базовому адресу чтоб получить реальный адрес
                                                Ответить
                                                • Если у тебя указатель умещается в uint8_t — может.
                                                  Ответить
                                                  • > указатель умещается в uint8_t

                                                    Не, он хочет что-то в духе кастомного std::vector::pointer. Чтобы там не настоящий поинтер был, а какой-то компактный тип, который можно через какую-то арифметику превратить в настоящий.

                                                    З.Ы. Ну кстати можно, походу. Этот тип из аллокатора берётся как раз. Если он будет вести себя как поинтер, то вектор схавает.
                                                    Ответить
                                                    • Хм, можня упороться ня отличненько: перегружаем new, чтобы принимал uint8_t, и унярный &, чтобы возвращал индекс элемента в каком-то статическом массиве.
                                                      Ответить
                                                  • > Если у тебя указатель умещается в uint8_t — может.

                                                    А если не уменьшается, и если я не хочу хранить полный указатель под каждую хрень? Есть один настоящий указатель, и куча смещений от него, и эти смещения влезают uint8_t без проблем.
                                                    Ответить
                                                    • > я не хочу хранить полный указатель под каждую хрень

                                                      Ну там в трейтах аллокатора можно указать свой тип для pointer. Может и прокатит что-то кастомное, если прикрутить звезду и скобочки.

                                                      Просто uint8_t нельзя, конечно. Но структурка или енум с uint8_t могут прокатить.
                                                      Ответить
                                                      • > Ну там в трейтах аллокатора можно указать свой тип для pointer. Может и прокатит что-то кастомное, если прикрутить звезду и скобочки.

                                                        Трейты-хуёйты, может и прокатит, а может не прокатит... Ясно всё.

                                                        Сколько надо будет с этим примерно ебаться, и много ли я от этого выиграю на своих задачах?
                                                        Ответить
                                                        • > Сколько надо будет с этим примерно ебаться

                                                          Х.з., я тут только пессимистичный прогноз могу дать. Наебавшись с тем же boost intrusive списком, я тупо выбросила его няхуй и написала свой за 5 минут.
                                                          Ответить
                                                    • А зачем аллокатору хранить указатель? Задача аллокатора — просто вернуть его, примерня как "return &static_arr[free_idx++]".

                                                      Кстати, std::list хранит ня указатели, а Allocator::pointer, так что можня попробовать упороться с таким аллокатором. Но лучше, конечно, использовать нярмальные intrusive list.
                                                      Ответить
                                                      • > зачем аллокатору хранить указатель

                                                        Списку, который на основе этого аллокатора работает, нужны указатели. Ну и тратить на них по 4 байта не хотелось бы, если список маленький.

                                                        > нярмальные intrusive list

                                                        Их, кстати, довольно сложно юзать в режиме "несколько списков через одни и те же объекты"... При том, что внутри там ерунда по переключению линков, которая пишется буквально за 5 минут (и в ней даже условий нет, так что юнит-тест элементарен). Ну в данной конкретной задаче может быть и прокатят.
                                                        Ответить
                                                      • intrusive это когда внутри объекта есть ссылки на тудой и сюдой?
                                                        Ответить
                                                        • > внутри объекта есть ссылки на тудой и сюдой

                                                          Да, ссылки ты размещаешь в объекте сам и поясняешь либе как ими пользоваться.
                                                          Ответить
                                                          • И экономишь этим лишние обращения?

                                                            Так-то ты мог свой итератор со своим ++ написать и в 03 еще
                                                            Ответить
                                                            • > экономишь этим лишние обращения

                                                              Скорее оставляешь управление памятью за собой, как в сишке. А "контейнер" даёт тебе attach/detatch вместо insert/remove.

                                                              В теории могло бы быть полезно, когда тебе надо 2-3 списка построить через одни и те же ноды. Но на практике мне не удалось запинать эти злоебучие трейты, пришлось решать эту задачу руками.
                                                              Ответить
                                                              • а, понял идею

                                                                Делаешь один связанный список, и по нему строишь два других списска: один напрямую, другой через один, например?
                                                                Ответить
                                                                • Ну тип того. Список проснувшихся тредов и список тредов в процессе, к примеру.

                                                                  Это всё решается и на обычных контейнерах, конечно. Но по памяти/пирфомансу будет совсем не айс.
                                                                  Ответить
                                                                  • А чем плохо вручную покласть их в кучу, а в контейнеры покласть на них ссылки/указатели?

                                                                    Тем, что придется обёртку делать на каждый такой указатель?
                                                                    Ответить
                                                                    • > вручную покласть их в кучу, а в контейнеры покласть на них ссылки/указатели

                                                                      Ну получается слишком много мелкой хуйни и аллокаций для неё. Если у тебя какие-нибудь треды тыщи раз в секунду просыпаются и засыпают, как-то стрёмно аллокатор дрочить каждый раз. Особенно если в этих местах аллокатор вообще трогать нельзя.

                                                                      А с интрузивом оно интегрировано в основную структуру. Ну как сишник бы сделал.
                                                                      Ответить
                                                                      • А, понятно: в intrusive я могу кучу вообще не трогать например (ну во всяком случае не аллочить ничего) и просто класть структуру, в указателе "next" которой будет именно нужное мне значение?
                                                                        Ответить
                                                                        • Ну да, в системном сишном коде этот паттерн очень часто встречается. Когда у тебя посреди большой структуры лежат какие-нибудь next/prev или left/right/parent от всяких разных "контейнеров", в которые она входит.

                                                                          А в самих "контейнерах", по сути, только башка этих списков/деревьев.
                                                                          Ответить
                                                                          • ну в общем intrusive это такой сахарок, чтобы вручную не разыменовывать указатели, а ходить по "виртуальным" контейнерам (небось еще итераторами и небось их можно сувать даже в стандартные алгоритмы)
                                                                            Ответить
                                                                            • Ну как-то так, да. Есть ещё intrusive аналог shared'а, в котором у тебя счётчик вшит в сам объект чтобы отдельный управляющий блок не городить. Ну или если у тебя счётчик уже есть (COM объект какой-нибудь).
                                                                              Ответить
                                                                              • забавно, я думал как-то как подружить Com c шариком, в итоге взял CComObject из ATL, он примерно это и делает
                                                                                Ответить
                                                                              • > intrusive аналог shared'а

                                                                                Спасибо, ты прям вернул говнокод 2010-го.
                                                                                Ответить
                                                                              • > intrusive аналог shared'а
                                                                                В крестах, кстати, есть std::make_shared(). По Стандарту std::make_shared() обязана делать только одну аллокацию, сшивая управляющий блок с данными. Так что shared_ptr, сделанный через make_shared(), и shared_ptr, сделанный через конструктор — две очень большие разницы.
                                                                                Ответить
                                                                                • уж не хочеш ли ты сказать, что интрузив не умела emplace?
                                                                                  Ответить
                                                                                  • https://habr.com/ru/post/509004/
                                                                                    Ответить
                                                                                    • >Если при этом в foo() возникнет исключение — получаем утечку экземпляра Bar.

                                                                                      блядь, какой С++ сложный

                                                                                      шарик помрет, потому что померло всё выражение, а Bar никто не делитнул, вот он и остался, верно?

                                                                                      шарик тут суть вообще временный обхект же
                                                                                      Ответить
                                                                                      • В том примере снячала выделяется память через new Bar, потом вызывается foo(), из няго вылетает исключение, и до конструктора std::shared_ptr указатель из new Bar просто ня доходит.
                                                                                        Во всяком случае, так было раньше, а теперь уже всё отличня.
                                                                                        > Начиная с c++17 утечка памяти в том хитром редком примере, ради которого в STL был добавлен std::make_shared, уже невозможна.
                                                                                        Ответить
                                                                                • Было смешно смотреть на "оптимизацию", где на большой ресурс, аллоцированный make_shared, сохраняли слабый указатель. По замыслу, если ресурс не нужен, то он разрушится и освободит память, а потом, если weak_ptr протухший, его можно заного загрузить.

                                                                                  Проблема в том что этот ресурс — по сути дела struct { char[8294400] }.
                                                                                  Ответить
                                                                                  • > то он разрушится и освободит память
                                                                                    > make_shared
                                                                                    Какой эпичный выстрел в ногу!
                                                                                    Ответить
                                                • ну двайте уже, изобретите сегментную адресацию

                                                  а потом дальние и ближние указатели
                                                  Ответить
                                          • > И собрать свою говнолибу.

                                            Которая не будет всякую ненужную питушню треботвать, и будет эффективна по потреблению памяти.
                                            Ответить
                                      • >Тебе ня придётся учить стандартную библиотеку, если каждый
                                        > раз ты пишешь стандартную библиотеку сам

                                        "В Go распространен подход к выполнению большенства рутинных задач явно, уменьшая сложность понимания кода"

                                        буду теперь форсить эту фразу везде
                                        Ответить
    • меня "begin()" & "end()" вседа выбешивали в С++. Не ужто так было струдно нормальный интератор заиплементировать.
      Ответить
      • > нормальный интератор

        Что понимается под "нормальным"? Убожество как в джаве, дотнете или скриптушне, которое только для последовательного обхода пригодно?

        Всё-таки крестовые итераторы пытались решить большую задачу, чем просто обход контейнера по порядку.
        Ответить
        • Нормальные итераторы, это, наверное, ranges.
          Ответить
        • > Всё-таки крестовые итераторы пытались решить большую задачу

          Пытались )))

          А какой должен быть нормальный итератор? Какую глобальную проблему решили итераторы в крестах, которую в скриптушне решить не смогли? Допустим, в питоне.
          Ответить
          • > Какую глобальную проблему решили итераторы в крестах

            Указать на слайс контейнера чтобы удалить его или заменить на что-то другое, к примеру. Или (осторожно) удалять элементы из контейнера прям во время его обхода. Или найти элемент в мапе и записать в него новое значение не делая повторный поиск. Или даже проделать над ними какую-то арифметику(!), если random access.

            В питоне, емнип, имея итератор ты вообще ничего не можешь сделать. Ну кроме как достать из него следующее значение.
            Ответить
            • В Питоне для этого несколько другие вещи используются. Но в 1998 году альтернатив особо не было.

              Итераторы в крестах предназначались, как точка кастомизации. Захотел сделать итератор, который проходит по вектору строк и выдаёт только слова, имеющиеся в словаре, приведённые к нижнему регистру. Или проходит сначала по нечётным, а потом по чётным индексам — сделал, передал в имеющуюся функцию и всё работает.
              Ответить
              • > проходит по вектору строк и выдаёт

                Ну просто для обхода хватило бы и убогого forward iterator'а, которым хвалятся джавы да питоны.

                Хотя... их итератор даже на forward не тянет т.к. его нельзя передать в какой-нибудь erase() или заюзать как границу для последующего поиска.
                Ответить
                • А ещё в питоне итераторы исключение кидают, когда кончаются.
                  Ответить
                  • Ааааа! Массив закончился! Мы все умрём!
                    Ответить
                  • А джаве они вроде говорят что "всё" спец методом
                    Но это не важно.

                    Важно, что они итераторы своего конца никогда не знают, и потому всякие крутые штуки как в крестах с ними не сделать
                    Ответить
                • вы знаете что такое принцим immutable object и зачем это надо?
                  Ответить
            • > Указать на слайс контейнера чтобы удалить его или заменить на что-то другое

              Такое есть в скрипушне, а ещё в «Nim», кажется.

              > Или (осторожно) удалять элементы из контейнера прям во время его обхода.

              Такого, кажется, в скриптушне действительно нет. Раньше же итератор протухал как только его коллекцию как-либо меняли? Тогда крутая фича.

              Хотя нет, в питоне можно вот так:
              array = [1, 2, 3, 4, 5]
              for e in array:
                  if e % 2 == 0:
                      array.remove(e)
              print (array) # [1, 3, 5]

              Это ведь итератор работает!

              > В питоне, емнип, имея итератор ты вообще ничего не можешь

              Это правда лишь отчасти. В питоне есть слайсы, генераторы и итераторы, которые делают всякие приколы. Я правильно понял, что «Ranges» просто совместил в себе все эти финтифлюшки? Справедливо ли утверждение, что крестобляди соснули, т.к. им пришлось комюпировать функционал из скриптушни? Или это скриптобляди поспешили и людей насмешили, а крестобояре обстоятельно подумали и сделали как надо?
              Ответить
              • Генератор/итератор в Питоне это, вроде как InputRange/ForwardRange в крестах (Не помню, копирование итераторов там починили или нет). Фактически это чаще всего используемая конструкция, но иногда хочется и к предыдущему элементу вернуться, и копию итератора сохранить. Передать итератор и построить кучу из последовательности, на которую он ссылается ЕМНИП в Питоне не получится.
                Ответить
              • > array.remove(e)
                Это удаление элемента по знячению. Об эффективнясти такого можня догадаться.
                Ответить
                • Для скриптуха это вполне допустимо

                  По идее нужно найти элемент за O(N) (если нет требования сортированности массива) и, удалив элемент, двигануть пол массива. Какой окшмар
                  Ответить
                  • А потом повторить для всех попавших под условие элементов. Один цикл — O(N^3), какое ня!
                    Ответить
                    • а он удаляет все или толкьо первый?

                      если все, то логично сначала все найти, потом подвигать.

                      А нельзя явно заказать линкдлист вместо массива, если уж мы такие удалятели знатные?
                      Ответить
                      • Только первый.

                        > А нельзя явно заказать линкдлист вместо массива, если уж мы такие удалятели знатные?
                        Нят. Это слишком сложня для скриптов.
                        Ответить
                        • Ну да, не стоит засирать мозг лишними типами данных

                          Именно потому я за перл: массив, хеш, да скляр. Всё
                          Ответить
                          • Поэтому я за "С" — массив. Всё. Мозг засирать нечем.
                            Ответить
                            • Ну кстати да.
                              Берешь, и делаешь нужную структуру под конкретную задачу

                              Потому мне всегда смешно от сёмных нахрюков про "в си даже мапы нету"

                              вон сколько сложностей возникло в крестах из за STL контейнеров
                              Ответить
                              • > в си даже мапы нету

                                А в позиксе есть! Правда она одна на весь процесс и удалять из неё нельзя. Но это мелочи.
                                Ответить
                                • да, ее надо целиком грохать

                                  там вроде и массив есть с байнари сёрчем... такие костыли, конечно
                                  Ответить
                                  • байнари сёрч и сортировка в С из коробки есть, костыли не нужны.
                                    Ответить
                                    • хуясе, bsearch часть сишки, а я думал чото, что позикса:-/
                                      Ответить
                                      • Ну глупо было бы завезти qsort но забыть про bsearch...
                                        Ответить
                                        • lsearch юникс
                                          bsearch сишка
                                          tsearch юникс
                                          qsort сишка

                                          ужасный раздрай) Правда, по заголовочному фалйу понятно


                                          А в Win32 есть какинито алгоритмы интересные?
                                          Или у MS позиция "юзайте STL, пишите на крестах"?
                                          Ответить
            • вы милок, попутали курсоры с итераторами. задача итератора это перебор елементов - не более того.
              Ответить
              • Ну можешь считать, что это курсоры, раз так больше нравится.
                Ответить
              • В C++ это, разумеется, ня так.
                auto map = std::map<std::string, std::string, std::less<>>{{"hello", "world"}, {"bye", "sun"}};
                auto iterator = map.find("bye");
                if (iterator != map.end()) {
                    map.erase(iterator);
                }
                Ответить
                • да даже в сраной джавке есть remove у итератора
                  Ответить
                • Увеличиваем степень наркомании:
                  CountingIterator<TransformIterator<StrideIterator<std::vector<int>::iterator>>> it {5, { squared, {3, cont.begin()}}};
                  Ответить
              • Что такое "курсор"? Что-то из СУБД?

                В С++ есть несколько категорий итераторов:
                https://www.geeksforgeeks.org/introduction-iterators-c/

                Самые тупые их них могут только выдавать значение (разыменовываться) или только двигаться вперед (++)

                Самые продвинутые умеют даже random access.
                Некоторые умеют писать или удалять данные

                Все зависит от категории.
                Ответить
                • Он на Википедии про курсоры прочитал. Я тоже оттуда брал нахрюки!
                  Ответить
                  • Я знаю только применительно к СУБД, и там действительно курсор именно то, о чём он говорит

                    https://docs.microsoft.com/en-us/sql/relational-databases/cursors?view=sql-server-ver15

                    3ацени, кстати, сколько их типов разных
                    Ответить
                • "задача итератора это дать универсальный интерфейс перебора(доступа) для разных имлементаций коллекторов. на этом ее задачи кончены". Изменение коллекций в обязанности итераторов не входит а наоборот они должны обеспечить сохранность данных без изменений
                  Ответить
                  • То есть по твоему определению:
                    * Доступа к возвращаемому значению генераторов посредством итераторов не сделать (ведь это, о боже, изменит значение генератора)
                    * Ленивых итераторов быть не может (ведь доступ к значению заставит это значение изменится, какой ужас)
                    * Абстрагировать поток как коллекцию значений с помощью итератора не получится (поток меняется от чересчур пристального взгляда на него, кошмар).

                    И нахуя нужны такие итераторы?
                    Ответить
                  • В таком случае итераторы в С++ не итераторы
                    Ответить
            • задача итератора это дать универсальный интерфейс перебора для разных имлементаций коллекторов. на это ее задачи кончены
              Ответить
        • > Что понимается под "нормальным"?

          Kiselyov zippers
          Ответить
          • легкий в имплементации и применении, интуитивный в использовании
            Ответить
    • "Welcome, please take your seats. Today's lecture is about Lazy Evaluation. The lecture is over, thank you for listening. Questions?"
      Ответить

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