Название: Итераторы Отправлено: Igors от Январь 28, 2021, 13:04 Добрый день
Есть большой класс, и в нем Код И есть метод Код С довольно содержательным телом цикла, переписывать его явно не хочется. (как и делать из тела метод) Требуется сделать так чтобы можно было крутить цикл и по selection, Код Но конечно без копирования содержательной части (тела цикла). Как это сделать итераторами или чем еще (в "современном С++") ? Спасибо Название: Re: Итераторы Отправлено: Авварон от Январь 28, 2021, 14:15 Ш - шаблоны
Название: Re: Итераторы Отправлено: RedDog от Январь 28, 2021, 16:53 Код: for (auto it = std::begin(container); it != std::end(container); ++it) Давно не видел void в скобочках. Название: Re: Итераторы Отправлено: Igors от Январь 29, 2021, 08:38 Код: for (auto it = std::begin(container); it != std::end(container); ++it) Давно не видел void в скобочках. Конечно "цена вопроса" невелика, есть неск приемлемых решений. Самое простое - конвертировать контейнеры в вектор указателей std::vector<CData *>. Ну будет какой-то оверхед, но не смертельный. Можно и просто "заткнуть" парой-тройкой if'ов, напр Код Это конечно явно "не общий случай", а вдруг надо еще какой-то контейнер парить? С др стороны пока не видно откуда ему взяться, все CData во владении CBigClass Просто бросается в глаза что нужно "итерироваться" причем всяко-разно. Нет ли чего-нибудь модного/элегантного ? Название: Re: Итераторы Отправлено: RedDog от Январь 29, 2021, 09:53 std::advance
std::next Название: Re: Итераторы Отправлено: Igors от Январь 29, 2021, 11:18 std::advance Не вижу как это поможет разрулить разные типы эл-тов. Если с темплейтами то может так "подмазать"std::next Код И вызывать Код Попинайте Название: Re: Итераторы Отправлено: RedDog от Январь 29, 2021, 11:23 SomeMethod сделать шаблонным, шаблоном туда передавать контейнер
Код: template<typename T> Название: Re: Итераторы Отправлено: Igors от Январь 29, 2021, 12:37 Код: template<typename T> Название: Re: Итераторы Отправлено: RedDog от Январь 29, 2021, 13:14 Касательно начала темы, там только 2 типа, CData и CData*
отделить одно от другого можно через std::is_pointer так же можно сравнить с нужным типом через std::is_same Название: Re: Итераторы Отправлено: Igors от Январь 29, 2021, 16:20 Касательно начала темы, там только 2 типа, CData и CData* Тогда зачем было заявлять общность (темплейт) если латаем? Залатать и так можно. Да и "отделить" с помощью std::is_pointer (или std::is_same) не так уж легко, просто "if" не получится, нужно городить что-то типа std::enable_if (помню смутно). Подозреваю что латка получится никак не меньше чем бесхитростная выше.отделить одно от другого можно через std::is_pointer так же можно сравнить с нужным типом через std::is_same Повторюсь, дело не в том что, мол, не знаю как решать, "памагите" :) Но хочется сделать вккуратно, а не развешивать сопли. Название: Re: Итераторы Отправлено: Old от Январь 29, 2021, 16:26 Но хочется сделать вккуратно, а не развешивать сопли. С теми требованиями из первого поста "вккуратно" не получится. Продолжайте развешивать сопли.Это прекрасное решение и всем, кто в дальнейшем будет читать этот код, все сразу будет понятно. :) Код
Название: Re: Итераторы Отправлено: RedDog от Январь 29, 2021, 17:34 https://en.cppreference.com/w/cpp/types/add_pointer
Опять не? Название: Re: Итераторы Отправлено: Igors от Январь 30, 2021, 10:00 https://en.cppreference.com/w/cpp/types/add_pointer Ну вот, сейчас начнетсяОпять не? Цитировать Уже столько вариантов предложили, а ему все не так! :)Но давайте все-таки посмотрим "что предложили". Ведь вся эта хренотень (is_pointer, add_pointer и.т.п.) - вовсе не обычные ф-ции которыми можно спокойно воспользоваться. Как я понимаю, они позволяют сделать темплейты что будут корректно вызываться для указателя и нет, но их надо еще делать, а как? (навскидку я не напишу) Во-вторых, как-то "не концептуально". Объявление template означает что можем подавать что угодно, во всяком случае - многое. В этом и кайф этого угребочного мета-программирования. А сами обеспечиваем лишь 2 варианта: ссылка и указатель. Потребуется напр по значениям мапы - и все. Да, конкретно для данной задачи нужны только 2 варианта, но если пердлагаем "общность" - то надо ее поддерживать Название: Re: Итераторы Отправлено: RedDog от Февраль 01, 2021, 09:20 Объявление template означает что можем подавать что угодно, во всяком случае - многое. Нет template говорит о том, что обработка переданных аргументов будет одинакова для разных типов.А внутренняя реализация обработки зависит от разработчика. Чем сильнее различается АПИ аргументов, тем больше будет геморроя при реализации. Название: Re: Итераторы Отправлено: Igors от Февраль 01, 2021, 11:09 Может лучше нацелить темплейт(ы) не на итератор, а на *итератор, т.е. разыменованную ссылку
Код Выглядит гораздо проще чем is_pointer и.т.п. (как то писать - хз, а покрывает лишь один случай) Однако же... как переменчива мода... Раньше страсти кипели, там всякие вариадики, SFINAE (если я правильно помню это слово), traits и еще бог весть что. А сейчас - та вроде никому это и не интересно. Мда... Название: Re: Итераторы Отправлено: Авварон от Февраль 01, 2021, 17:14 можно просто перегрузить функцию для ссылки и указателя без шаблонов=)
Код: void foo(Type &t) {...} Название: Re: Итераторы Отправлено: Igors от Февраль 03, 2021, 07:47 можно просто перегрузить функцию для ссылки и указателя без шаблонов=) ??? Не уловил идеюКод: void foo(Type &t) {...} Название: Re: Итераторы Отправлено: Fregloin от Февраль 15, 2021, 13:08 Вам уже указали решение вашей пробелмы - std::advance
Название: Re: Итераторы Отправлено: Igors от Февраль 15, 2021, 14:13 Вам уже указали решение вашей пробелмы - std::advance "А можно пример?" :) Потому что не вижу каким боком здесь поможет advanceИ что там за "плохо скрываемое раздражение"? :) Нет удобного решения - ну у меня его тоже нет. Название: Re: Итераторы Отправлено: Racheengel от Апрель 15, 2021, 12:02 Навеяло:
Джун: так, сейчас по быстрому наговнокодим, так, ну скомпилилось, ну вроде не падает... иногда... фух, в продакшен. Мидл: так, что эти джуны там наваяли, ой блин, говнокод, лапша, нет структуры и ПолётаМысли... Ну ща тут абстрактную шаблонную фабрику прикрутим, там визитор, тут обсервер... 95 из 100 тестов прошло, значит уже хорошо, эй, менеджер, готово! Синьйор: так, блин, что за GOFнокод... Фабрики в лес, визиторы в лес, оставим пару классов, чтобы KISS и иже с ним... Ага, раз в 50 быстрее работает... готово :) Тимлид: народ, давайте-ка код ревью по быстрому проведём, а то отдавать скоро. Начальник разработки: так, что там в задаче сказано? А, найти площадь прямоугольника. Где там мой калькулятор... Название: Re: Итераторы Отправлено: AkonResumed от Апрель 19, 2021, 22:51 Цитировать struct CBigClass { ... QList<CData> mData; QSet<CData *> mSelection; ... }; Я бы сделал так: Код: struct CBigClass { Теперь тип элемента в контейнерах, можно сказать, одинаковый. Если QSet<CData *> mSelection; нужно оставить, то сделайте zero-cost адаптер, чтобы оперировать ссылками, а не указателями: Код: struct CBigClass { Итак, std::reference_wrapper внутренне реализован как указатель, но имеет семантику ссылки. Собственно, она часто и используется с контейнерами. Теперь адаптер: он не имеет накладных расходов (ссовсем), поскольку размер std::reference_wrapper == размеру указателя, и мы жестко реинтерпретируем. Но равенство размеров не гарантируется (не уверен), поэтому мы это проверяем в compile-time static_assert-ом. И еще. В вашем QSet<CData *> mSelection; могут быть нулевые указатели? Предполагаю - нет. Если указатель не может быть нулевым - используйте ссылку (во всех таких случаях). Читаемость и строгость кода же повышаются. Хотя, в плане читаемости - спорно (std::reference_wrapper<> - много букв :)). Название: Re: Итераторы Отправлено: Igors от Апрель 20, 2021, 11:00 Да, интересный приемчик с reference_wrapper, не знал, спасибо
Название: Re: Итераторы Отправлено: AkonResumed от Апрель 20, 2021, 11:08 Не вопрос. Да и это делеко не последний писк моды - это c C++11.
Название: Re: Итераторы Отправлено: Авварон от Апрель 20, 2021, 12:41 Код: return reinterpret_cast<QSet<std::reference_wrapper<CData>>&>(mSelection); Это UB Название: Re: Итераторы Отправлено: AkonResumed от Апрель 20, 2021, 14:24 Это не UB. В худшем (маловероятном) случае, это compile-time error. Потому что так перед грязным хаком (reinterpret_cast) идет
Код: static_assert(sizeof(CData*) == sizeof(std::reference_wrapper<CData>)); Если уж подходить совсем параноидально, то в теории UB возможен, но такая реализация std::reference_wrapper лишена практического смысла. Например, std::reference_wrapper хранит не исходный указатель, а смещенный на 5, например, или в форме инверсных битов. Название: Re: Итераторы Отправлено: Old от Апрель 20, 2021, 14:45 Ну это все таки грязный хак. :)
А что если у QSet для указателей и нет разные специализации? Название: Re: Итераторы Отправлено: Авварон от Апрель 20, 2021, 15:04 Это UB, в общем случае нельзя делать reinterpret_cast между unrelated типами.
https://en.cppreference.com/w/cpp/language/reinterpret_cast Цитировать std::pair<int, int> and std::pair<const int, int> are not similar. Компилятор предполагает что 2 ссылки/указателя на различные типы не могут ссылаться не одну область памяти (strict alias rule) и строит на этом оптимизации. reinterpret_cast ломает это предположение - если компилятор тупенький и не оптимизирует, то это будет работать, если умный, то сломается. UB. Название: Re: Итераторы Отправлено: Авварон от Апрель 20, 2021, 15:09 Ну или более сложный пример, вы знаете что на вашей платформе sizeof(bool) == sizeof(int8_t) (ну или char).
Значит вы можете сделать Код: vector<bool> bools; Название: Re: Итераторы Отправлено: AkonResumed от Апрель 20, 2021, 15:53 А что если у QSet для указателей и нет разные специализации? Ах, таки вы меня подсекли! Про возможную специализацию внешнего типа я упустил. В данном случае специализации QSet нет, работать будет. Но в общем случае - да, это нужно учитывать. Авварон, Код: vector<bool> bools; По поводу strict alias rule и оптимизации (привет restrict poiners): А как вы соотнесете это с placement new(), например? Название: Re: Итераторы Отправлено: Авварон от Апрель 20, 2021, 16:03 Ах, таки вы меня подсекли! Про возможную специализацию внешнего типа я упустил. В данном случае специализации QSet нет, работать будет. Но в общем случае - да, это нужно учитывать. Там внутри могут быть всякие traits которые для разных типов разные.Но в любом случае, даже если битовое представление одинаковое, это UB. По поводу strict alias rule и оптимизации (привет restrict poiners): А как вы соотнесете это с placement new(), например? В чем проблема-то? Единственный валидный юзкейз reinterpret_cast между разными типами это каст к массиву байт (или void*) и обратно. Компилятор знает что вон тот char buffer[] потенциально может алиаситься с вот этим указателем и сгенерит менее производительный код. placement new как раз подпадает под это - буфер чаров может алиаситься (и делает это) с указателем на произвольный T. А вот любые другие типы (например int* в double*) алиаситься не могут. Название: Re: Итераторы Отправлено: AkonResumed от Апрель 20, 2021, 22:35 Цитировать Там внутри могут быть всякие traits которые для разных типов разные. Могут, но это лишено практического смысла. Для контейнера важен только размер элемента (точнее, скажем "семантический размер", как в случае с bool), а сам элемнт, будь хоть POD, хоть класс с VMT - в плане хранения - все равно. Если обратное, то это уже не контейнер, а контейнер + еще что-то (т.е. bad design). Но в любом случае, даже если битовое представление одинаковое, это UB. Цитировать В чем проблема-то? Единственный валидный юзкейз reinterpret_cast между разными типами это каст к массиву байт (или void*) и обратно. Я к тому, что поинтер-алиасинг это не только про reinterpret_cast. Вот этот код дает UB (печатает -1 вместо ожидаемого 0) в обоих случаях (MinGW 8.3, O2):Компилятор знает что вон тот char buffer[] потенциально может алиаситься с вот этим указателем и сгенерит менее производительный код. placement new как раз подпадает под это - буфер чаров может алиаситься (и делает это) с указателем на произвольный T. А вот любые другие типы (например int* в double*) алиаситься не могут Код: #include <iostream> А теперь вернусь в контекст нашей задачи - слегка модифицирую код на манер std::reference_wrapper, для упрощения я использовал просто структуру: Код: #include <iostream> Почему больше нет UB? - сходу не найду - но еще вроде со всремен C++11 правил алиасинга если один из типов агрегатный и включает другой членом - то это не UB. Итого: Типы reference_wrapper<T> и Т* должны быть безопасны в плане reinerpret_cast, т.к. первый инкапсулирует второй как член, что следует из того, что sizeof(reference_wrapper<T>) == sizeof(Т*)т.е. reference_wrapper<T> никак не может быть реализован по-другому, кроме как инкапсулировать указатель и больше ничего. Название: Re: Итераторы Отправлено: AkonResumed от Апрель 20, 2021, 23:00 От-т! Опять я упустил внешний контейнер (QSet).
Авварон, по алиасингу вынужден с вами также согласиться. Друзья, спасибо! Название: Re: Итераторы Отправлено: Igors от Апрель 21, 2021, 10:12 Код: *i = -1; Пример vector<bool> приводится так часто/неизменно, что скорее говорит о том что никаких других просто нет :) С placement new как-то не уловил, неплохо бы пожевать. Спасибо От-т! Опять я упустил внешний контейнер (QSet). Типа "а вот возможен такой контейнер что будет иметь какие-нить traits - и тогда заклинит"? Может и да, но лично меня это совершенно не волнует. Я не собираюсь лепить врапперы всегда и везде, речь идет о конкретном случае в котором он весьма кстати. А объявить любой reinterpret_cast UB/хаком никакого ума не требует. Заметьте что чем больше человек говорит о корректности - тем меньше решений предлагает. Такой подход не конструктивен. Цитата: AkonResumed link=topic=32938.msg244690#msg244690 Авварон, по алиасингу вынужден с вами также согласиться. Друзья, спасибо! Возможно/предполагаю, Вы почувствовали что разбор этих тонкостей (или толстостей) отнимает слишком много времени, а работа-то стоит. Да, согласен :)Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 10:21 Может и да, но лично меня это совершенно не волнует. Я не собираюсь лепить врапперы всегда и везде, речь идет о конкретном случае в котором он весьма кстати. Да вы можете это брать и использовать. :)Дальнейшее обсуждения больше для разработчиков, что бы никто из них по неосторожности у себя не задействовал. Название: Re: Итераторы Отправлено: Racheengel от Апрель 21, 2021, 10:36 Цитировать Вот этот код дает UB (печатает -1 вместо ожидаемого 0) Почему UB? Он и должен выводить -1. В коде же явно написано "*i = -1", а i передаётся поинтером 1 в 1. Другое дело, что такой код в продакшене никто использовать не будет. Разве что как тест для компилятора. Название: Re: Итераторы Отправлено: AkonResumed от Апрель 21, 2021, 10:53 UB, потому что следом *f = 0.0f; зануляет туже самую область памяти. Так и происходит, но компилятор, при возврате в return *i; попросту не перезагружает значение из памяти, потому как считает, что f не может указывать на ту же ячеку, что и i, соответственно, она не может быть изменена через f. Для return *i; компилятор просто хардкодит 1 в eax/rax (регистр, через который идет возврат значения функции).
Название: Re: Итераторы Отправлено: AkonResumed от Апрель 21, 2021, 11:02 Да, и порядок выполнения операций здесь не при чем. Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык. UB возникает именно из-за оптимизатора и формального правила стандарта, которое он использует для оптимизации.
Название: Re: Итераторы Отправлено: Igors от Апрель 21, 2021, 11:23 Да, и порядок выполнения операций здесь не при чем. Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык. UB возникает именно из-за оптимизатора и формального правила стандарта, которое он использует для оптимизации. Не уверен. Вот был интересный случайКод Эта ошибка долго оставалась незамеченной, но когда перешел на шланг - тот выдал варнинт, молодец. Конечно в в любом случае перекрывать адреса = ненужный поиск приключений. Вообще употребляемые здесь слова "продакшн", "разработка" и.т.п. - это просто "надувание щек", здесь обсуждается всего лишь мелкая деталь :) Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 11:28 Вообще употребляемые здесь слова "продакшн", "разработка" и.т.п. - это просто "надувание щек", здесь обсуждается всего лишь мелкая деталь :) Боже, от вас слышать про надувание щек... :)Название: Re: Итераторы Отправлено: AkonResumed от Апрель 21, 2021, 11:29 И как вы предполагали - какой Rand будет вызван первым - левый или правый?
Название: Re: Итераторы Отправлено: AkonResumed от Апрель 21, 2021, 11:41 В этом контексте (порядка вычисления аргументов) частая ошибка, допускающая лик:
Код: void foo(std::shared_ptr<MyClass> c, int x); Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 11:47 Вот этот код дает UB (печатает -1 вместо ожидаемого 0) в обоих случаях (MinGW 8.3, O2): Да, прикольно, не задумывался о том что placement new можно звать на unrelated типах. Небось тоже где-то прописано что так делать нельзя (кроме char*/void*) Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 11:52 И как вы предполагали - какой Rand будет вызван первым - левый или правый? В 2ГИСе мы спрашивали похожую задачку std::cout << f() << f() << f() << std::endl; где f() имеет сайд-эффект (делает i++) никто не решил (я в том числе) Название: Re: Итераторы Отправлено: Igors от Апрель 21, 2021, 11:58 И как вы предполагали - какой Rand будет вызван первым - левый или правый? Мне все равно (будет надо - посмотрю в отладчике), главное рез-т должен быть воспроизводимым при том же seed.Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык. Это противоречит духу/идее "конвейера". Во всяком случае "распаковкой операндов" для последующих команд(ы) процессор занимается.никто не решил (я в том числе) Любая задача имеет по меньшей мере одно решение: снятие самой задачи/проблемы. Здесь оно и будет лучшим - не нужны такие заморочки.Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 12:03 Любая задача имеет по меньшей мере одно решение: снятие самой задачи/проблемы. Здесь оно и будет лучшим - не нужны такие заморочки. Ну там задачи были разной сложности что позволяло оценить уровень кандидата. Полезно иметь задачу с подвохом ультимативной сложности. Если человек скажет какой-то один из возможных вариантов, то норм (там еще надо продраться сквозь код же), а если про точки следования вспомнит - ваще бох. Правда на моей памяти никто без подсказок не вспомнил, но это и не особо влияло. Название: Re: Итераторы Отправлено: Igors от Апрель 21, 2021, 12:17 Ну там задачи были разной сложности что позволяло оценить уровень кандидата. Полезно иметь задачу с подвохом ультимативной сложности. Если человек скажет какой-то один из возможных вариантов, то норм (там еще надо продраться сквозь код же), а если про точки следования вспомнит - ваще бох. Правда на моей памяти никто без подсказок не вспомнил, но это и не особо влияло. Заинтриговали :) По-моему без затей, слева направо, зачем прилагать усилия хранить то что еще нельзя слить. К сожалению, тесты никак не оценивают инициативность, способность находить решения и многое другое, тупенькое "знание справочника" обычно рулит :'( Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 13:31 В 2ГИСе мы спрашивали похожую задачку Нужно было вспомнить, что эта запись сахар для такой :)std::cout << f() << f() << f() << std::endl; где f() имеет сайд-эффект (делает i++) никто не решил (я в том числе) Код А они всегда выполняются слева направо, т.к. здесь следующий оператор всегда применяется к результату предыдущего. А вот с boo( f(), f(), f() ), не все так однозначно и, если мне не изменяет память, это отдается на откуп компилятора. Как правило f() будет вызываться справа налево, по крайней мере я не знаю ни одного компилятора, у которого это не так. Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 15:15 Нужно было вспомнить, что эта запись сахар для такой :) Код
Да, но нет, это не члены класса а свободные функции: Код и что выполнится вначале - operator<<( std::cout, f() ) или f() - бабка надвое сказала Название: Re: Итераторы Отправлено: Igors от Апрель 21, 2021, 15:22 Вспомнилось что когда-то весьма усердно изучалось нечто вроде
Цитировать Pascal передает параметры слева направо, стек очищает сама ф-ция. А вот С - справа налево и стек очищает вызывающий. Поэтому можно передавать переменное число параметров и.т.д и.т.п. (потом еще для калбэков надо было учитывать) Ну может какой-то смысл в этом и есть, но в принципе это совершенно бесполезное забивание головы всякой фигней :)Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 15:22 Да, но нет, это не члены класса а свободные функции: А у какого компилятора operator<< это свободная функция?У gcc и clang это члены класса. Даже у msvc это член класса. и что выполнится вначале - operator<<( std::cout, f() ) или f() - бабка надвое сказала Что вначале выполниться boo или f? :)Код
а здесь: Код
Даже в вашем варианте порядок вызовов четко определен. :) Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 15:23 Вспомнилось что когда-то весьма усердно изучалось нечто вроде Да-да, продолжайте наблюдение. :)Цитировать Pascal передает параметры слева направо, стек очищает сама ф-ция. А вот С - справа налево и стек очищает вызывающий. Поэтому можно передавать переменное число параметров и.т.д и.т.п. (потом еще для калбэков надо было учитывать) Ну может какой-то смысл в этом и есть, но в принципе это совершенно бесполезное забивание головы всякой фигней :)Название: Re: Итераторы Отправлено: AkonResumed от Апрель 21, 2021, 16:33 Кстати, при прочих равных (когда нет выделения общих вычислений на аргументах) на практике соглашение о вызове по идее должно коррелировать с порядком вычисления аргументов - тот, который пушим первым первым и вычисляем, но не вычисляем первым аргумент из середины, т.к. его нельзя сразу запушить. Но, например, при register calling convension то, что будет передаваться в регистрах можно вычислять в любом порядке. Так что вариаций много.
Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 16:37 Кстати, при прочих равных (когда нет выделения общих вычислений на аргументах) на практике соглашение о вызове по идее должно коррелировать с порядком вычисления аргументов - тот, который пушим первым первым и вычисляем, но не вычисляем первым аргумент из середины, т.к. его нельзя сразу запушить. Но, например, при register calling convension то, что будет передаваться в регистрах можно вычислять в любом порядке. Так что вариаций много. Как я помню, это отдается на откуп компилятора. Поэтому может быть что угодно, закладываться на это нельзя.Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 17:00 Даже в вашем варианте порядок вызовов четко определен. :) Ну вот gcc 4.6 печатает "210", а 10.3 печатает "120" https://godbolt.org/z/Pc9fa4bf9 Там в целом были какие-то изменения в с++11, но яхз, поправлено это или "везет" что все новые компиляторы печатают одинаково. Что вначале выполниться boo или f? Улыбающийся вот только оператор (даже член класса) это функция от двух аргументов Код: foo(f(), g()); Название: Re: Итераторы Отправлено: Racheengel от Апрель 21, 2021, 17:08 И как вы предполагали - какой Rand будет вызван первым - левый или правый? В 2ГИСе мы спрашивали похожую задачку std::cout << f() << f() << f() << std::endl; где f() имеет сайд-эффект (делает i++) никто не решил (я в том числе) И в чём проблема? Это пайплайн. Он должен выполняться строго слева направо (ибо в этом его суть) и никак иначе. Сайд-эффект в чём? Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 17:09 Ну вот gcc 4.6 печатает "210", а 10.3 печатает "120" https://godbolt.org/z/Pc9fa4bf9 Увидел где 210. вот только оператор (даже член класса) это функция от двух аргументов Код: foo(f(), g()); Название: Re: Итераторы Отправлено: Авварон от Апрель 21, 2021, 17:11 у вас в обоих случаях 10.3 (см правый pane)
Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 17:22 Да, жесть. Нужно быть осторожным. :)
За такое, конечно нужно яйца откручивать gcc-шникам. :) Спасибо хоть gcc с 7.1 начал нормальный код генерить. Название: Re: Итераторы Отправлено: Old от Апрель 21, 2021, 17:56 И в чём проблема? Это пайплайн. Он должен выполняться строго слева направо (ибо в этом его суть) и никак иначе. Сайд-эффект в чём? В том, что gcc до 7.1 лажал и генерировал шляпу. :)Название: Re: Итераторы Отправлено: Racheengel от Апрель 21, 2021, 23:30 И в чём проблема? Это пайплайн. Он должен выполняться строго слева направо (ибо в этом его суть) и никак иначе. Сайд-эффект в чём? В том, что gcc до 7.1 лажал и генерировал шляпу. :)А. Тогда стыдно им всем. Должно бы быть... Название: Re: Итераторы Отправлено: Old от Апрель 22, 2021, 07:02 Там в целом были какие-то изменения в с++11, но яхз, поправлено это или "везет" что все новые компиляторы печатают одинаково. Конечно поправили, gcc до 7 генерировал неправильный код.В случае с стримами порядок вызовов функций четко определен. Код
Если в b() генерируется исключение, то в потоке должен остаться результат от a(). А теперь посмотрите что кодогенерит gcc до 7. :) Название: Re: Итераторы Отправлено: Igors от Апрель 22, 2021, 07:19 Надеюсь "волна" прошла и можно поговорить о другом. Для удобства повторю часть стартового поста
Есть большой класс, и в нем А насколько вообще хорош (правомерен и.т.п.) такой выбор контейнеров? Код
Увы, подозреваю что словоохотливость сразу упадет до нуля. Ну конечно "надо знать задачу" (дежурная отмазка). Да задача самая банальная и которая есть у всех. Есть объекты, они рисуются в окнах и их список предъявляется юзеру (QTreeWidget), конечно их можно выбирать, добавлять, удалять, редактировать. CData - обычный себе объект, не маленький но и не большой. Единственная специфика - их может быть неприятно много (порядка 100К и больше), поэтому простецкий selectItem не катит в UI. So ? Название: Re: Итераторы Отправлено: Old от Апрель 22, 2021, 07:28 А насколько вообще хорош (правомерен и.т.п.) такой выбор контейнеров? Он великолепен. :)Основная ваша проблема в этом: (как и делать из тела метод) Как только вы сделаете отдельный метод, все у вас начнет получаться. :)Название: Re: Итераторы Отправлено: Авварон от Апрель 22, 2021, 10:55 Если в b() генерируется исключение, то в потоке должен остаться результат от a(). А теперь посмотрите что кодогенерит gcc до 7. :) Ну да, но это с с++11, на тот момент задача была валидная. Я таки носили простыню про sequencing, пункт 19 https://en.cppreference.com/w/cpp/language/eval_order Но надо понимать что это поправили только для operator<< и >>, для operator+ порядок по-прежнему не задан. Название: Re: Итераторы Отправлено: Авварон от Апрель 22, 2021, 11:02 So ? Код: void doWork(const CData &data) Название: Re: Итераторы Отправлено: Igors от Апрель 22, 2021, 11:21 Код: .. Цитировать Can you read, or only write? :)Название: Re: Итераторы Отправлено: Авварон от Апрель 22, 2021, 11:26 с 50% вероятностью ответ нет
Название: Re: Итераторы Отправлено: Igors от Апрель 23, 2021, 08:44 с 50% вероятностью ответ нет Не думаю здесь есть какие-то "варианты зависящие от задачи". Напр "в вдруг требуется пулеметная вставка/удаление?". Да, так бывает, но вряд ли такой контейнер дается юзверю в UI. А так надо лишь позаботиться чтобы multiply вставки/удаления выполнялись за один проход. Или популярная байка "std::vector лучше" (чем QList). В данном случае не вижу чем. "Нормальные" объекты в (подавляющем) большинстве случаев должны быть неперемещаемы. Замена QList<CData> на std::vector<CData *> дает немного больше возможностей, но заметно напрягает с удалением Рекомендация выше юзать ссылку (вместо указателя). Обычно я охотно это делаю, но в данном случае это "создает впечатление владения", а selection ну вот никак не владеет. Некоторый минус - QSet жрет многовато памяти при обильном selection. Что же нового/современного можно использовать? (вместо структур > 10 летней давности). Конечно "с выгодой", а не так, абы накрутить. Выходит что здесь и ничего. Или может задача "ну совсем уж серая, банальная", для нее и старого хватит? Или как? Название: Re: Итераторы Отправлено: Old от Апрель 23, 2021, 09:18 Что же нового/современного можно использовать? (вместо структур > 10 летней давности). Для того, что бы появились новые структуры данных, эти новые структуры сначала должен кто-то придумать.Т.к. от std-шников ждать ничего не приходится, то остаетесь только вы. :) А как придумаете, то std-шники сразу эти новые структуры реализуют в своем убогом std. :) Название: Re: Итераторы Отправлено: Racheengel от Апрель 23, 2021, 11:20 Что же нового/современного можно использовать? (вместо структур > 10 летней давности). Конечно "с выгодой", а не так, абы накрутить. Выходит что здесь и ничего. Или может задача "ну совсем уж серая, банальная", для нее и старого хватит? Или как? Вот вообще не понимаю проблемы, если честно. Есть два вида массивов: со ссылками и с указателями. Элементы обрабатываются одинаково. Вывод: обработчик элементов должен быть общий, циклы - разнесены. for (auto& item: mData) processItem(item); и for (auto* item: mSelection) processItem(*item); И всю обработку столкать в void processItem(CData& item). Если надо, processItem к тому же можно сделать виртуальной, чтобы в возможных наследниках можно было бы (теоретичски) менять поведение. Название: Re: Итераторы Отправлено: AkonResumed от Апрель 23, 2021, 11:26 Цитировать Рекомендация выше юзать ссылку (вместо указателя). Обычно я охотно это делаю, но в данном случае это "создает впечатление владения", а selection ну вот никак не владеет. Некоторый минус - QSet жрет многовато памяти при обильном selection. В этом правда есть.Изложу лишь следущее: если бы selection был владеющий отдельной копией объекта, т.е. QSet<CData> (не CData*) - это как-то принципиально сломало бы ваш код? Предположу, что нет. Указатель вы используете для уменьшения потребления памяти, ну и бонусом хэш-функция уже есть. Т.е. использование в selection указателей или самих данных определяется их размером, что, согласитесь, семантически ничтожный аргумент. Поэтому ссылка в данном случае - это эффективное владение. Я допускаю, что выбор указателя может быть как-то связан с хэшированием, например CData неуникальны. Или для них нетривиально придумать хорушую хэш функцию. Ваш код был бы проще, если бы было единообразие, которое позволило бы единую обработку шаблонной функцией без is_pointer: Код: struct CBigClass { Порядок таков, что если CData - это класс-сущность (identity class), то используются указатели, если класс данных - то сами классы. Цитировать Не думаю здесь есть какие-то "варианты зависящие от задачи" От специфики задачи зависит, порой, все :) Если у вас часто случаются пулеметные вставки, может рассмотреть вариант сперва сформировать вставку в виде вектора, а потом вставить ее в контейнер как единое целой, т.е. никаких multiply вставок?Цитировать Или популярная байка "std::vector лучше" (чем QList). Ну как байка? Например, в QList не засунешь std::unique_ptr, а std::unique_ptr в контейнере - это сплошь и рядом. Да, вы можете засунуть std::shared_ptr/QSharedPointer - но это другая (более широкая) семантика, да и код будет менее эффективным.Например, QList нет еmplace, а еmplace, в свою очередь, может оказаться решающим доводом в пользу типа данных контейнера, соот-но QList дает меньшую свободу. Название: Re: Итераторы Отправлено: Igors от Апрель 23, 2021, 15:05 И всю обработку столкать в void processItem(CData& item). Такой processItem может потребовать пяток-десяток доп аргументов что вычисляются в caller'e до цикла Вот вообще не понимаю проблемы, если честно. Нет какой-то "большой проблемы", просто хочется писать удобнее/приятнее, это нормально. Напр хорошо бы такКод А вместо этого тело выделяй, темплейты заряжай, еще и "сбоку бантик" в виде is_pointer. Где же хваленая гибкость итераторов? Ваш код был бы проще, если бы было единообразие, которое позволило бы единую обработку шаблонной функцией без is_pointer: Конечно, проблему стартового поста это решает. Но какой ценой, не получу ли др минусы? Напр первый вариант (оба эл-та указатели) перекладывает работу (во всяком случае часть) на внимательность программиста - в одном контейнере erase должен сопровождаться удалением, в др нет. С враппером выглядит заманчиво, но пока не пробовал, не знаю что там может полезет.Цитата: AkonResumed link=topic=32938.msg244746#msg244746 Например, в QList не засунешь std::unique_ptr .. Да, есть новые вкусные плюшки :) Но нужны ли они для данных стартового поста? Это стандартная задача "предяъвить список объектов", не ошибусь если скажу что ее делал каждый присутствующий. Что станет лучше от использования "новых" средств и каких ?... Например, QList нет еmplace ... Название: Re: Итераторы Отправлено: Racheengel от Апрель 23, 2021, 15:09 А что мешает тогда создать временный вектор поинтеров на mData? Это всего-то 2 строчки кода..
QList<CData*> dataList; for (auto& data: mData) dataList << &data; ну и дальше где нужно выбирать: auto & dst = useSelection ? mSelection : dataList; for (auto & data : dst) { .. } Название: Re: Итераторы Отправлено: Igors от Апрель 23, 2021, 15:11 ..что мешает тогда создать временный вектор .. Угрызения совести :) Все-таки это говнокодНазвание: Re: Итераторы Отправлено: Old от Апрель 23, 2021, 15:21 Угрызения совести :) Все-таки это говнокод Я на это смотрю и думаю: Да, этому парню говнокод не предложишь. Код
Название: Re: Итераторы Отправлено: Racheengel от Апрель 23, 2021, 17:40 ..что мешает тогда создать временный вектор .. Угрызения совести :) Все-таки это говнокодНу, это скажем так, простое решение малой кровью (без лишних классов-итераторов-шаблонов). Но лучшим решением было бы void processItem(CData& item). Название: Re: Итераторы Отправлено: Igors от Апрель 24, 2021, 06:45 Да, совсем забыл привести свое решение. Начнем с этого
Код
Код: void CBigClass::SomeMethod( bool useSelection ) Название: Re: Итераторы Отправлено: AkonResumed от Апрель 24, 2021, 12:02 С вашего позволения вернусь к обозначенной проблеме UB reinterpret_cast'a. Изначальный вариант:
Код: QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() Код: QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() Или эквивалент (м.б. более понятный): Код: QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() Естественно, после оптимизации новый вариант относительно старого не должен иметь никаких дополнителных расходов. Остается только одна потенциальная проблема - возможная специализация контейнера для указателей. В принципе, ее легко решить, если сделать свою специализацию контейнера для std::reference_wrapper<CData>, которая будет иметь битовую идентичность с контейнером CData*. Но это лениво (много букв). Название: Re: Итераторы Отправлено: AkonResumed от Апрель 24, 2021, 14:28 Да, и в С++20 это делается уже так (std::bit_cast):
Код: QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() Еще вариант (ИМХО, в общем случае малоприемлемый) - выключить strict type aliasing опцией компилятора. Ядро Линукса, например, компилится с -fno-strict-aliasing, а там, как можно догадаться, еще те любители реинтерпретации. Название: Re: Итераторы Отправлено: Igors от Апрель 24, 2021, 14:52 Фишка этого приема в том, что memcpy() дает понять компилятору, что alias стартует как тип src, т.е. QSet<CData*>*. По-моему memcpy просто "соответствует своему названию" - и все. Каким образом он может что-то "дать понять" ???. Также что значит "стартует как" ???Ну размеры эл-тов равны - и все, приводим, не понял чего Вы еще опасаетесь? Мифических хвостов? В общем - поясните Название: Re: Итераторы Отправлено: AkonResumed от Апрель 24, 2021, 15:46 Цитировать "стартует как" Код: void* p; // declaration Вот здесь по сути вопроса изложено четко и с примером: https://en.cppreference.com/w/cpp/string/byte/memcpy Название: Re: Итераторы Отправлено: Igors от Апрель 24, 2021, 16:58 Код: void* p; // declaration Вот здесь по сути вопроса изложено четко и с примером: https://en.cppreference.com/w/cpp/string/byte/memcpy Название: Re: Итераторы Отправлено: AkonResumed от Апрель 24, 2021, 21:57 Те же яйца, только в профиль:
Код: int i; memcpy: Notes std::memcpy may be used to **implicitly create** objects in the destination buffer. ... Where strict aliasing prohibits examining the same memory as values of two different types, std::memcpy may be used to convert the values. И далее почитать по ссылке https://en.cppreference.com/w/cpp/language/object#Object_creation что такое объекты и как они создаются. Название: Re: Итераторы Отправлено: Igors от Апрель 25, 2021, 08:19 Те же яйца, только в профиль: И что? Ну присвоили void * адрес чего-то, на здоровье. Но никаких "вытекающих" из этого нет, поведение p будет точно таким же как и при любой другой его установке. Неявное создание с помощью memcpy - ну да, если объект "тривиально копируемый" (как сейчас говорят), то можно и так, хотя времена таких трюков давно прошли, ну разве в контейнере чтобы пошустрее.Код: int i; И тот reinterpret_cast, нафиг он нужен? Тем более memcpy. Да просто так Код И вся любовь. Название: Re: Итераторы Отправлено: Old от Апрель 25, 2021, 09:02 И тот reinterpret_cast, нафиг он нужен? Тем более memcpy. Да просто так Точно.Код И вся любовь. А придурки из комитета все какие то касты придумывают, то static_cast, то reinterpret_cast, сейчас bit_cast придумали. Нечем им заняться. :) Зачем? Если можно сишным кастануть и вся любовь. :) Название: Re: Итераторы Отправлено: AkonResumed от Апрель 25, 2021, 09:59 Да, любовь - странная штука:
Код: #include <QSet> Название: Re: Итераторы Отправлено: Igors от Апрель 25, 2021, 10:41 Этот код дает UB при -O2. С перекрытием полей много чего "дают" (правда никто не хочет "получать"). Как бы Вы ни крутили, смысл один - вот эта "ячейка памяти" должна трактоваться как "нужный тип", без всяких изменений. Сишный каст это делает (в крайнем случае через void *) - ну и слава богу. Разве Вы не чувствуете что "порог сложности" давно уже пройден? Не нужно решение такой ценой, даже если оно 100% корректно. И вообще, чего Вы уперлись в эту мелочь? Вот сегодня создал тоже интересную темку. А какая шикарная тема про интеграцию скриптов. Был бы умный человек, а о чем с ним поговорить - я найду, не переживайте :) Название: Re: Итераторы Отправлено: Old от Апрель 25, 2021, 11:05 Разве Вы не чувствуете что "порог сложности" давно уже пройден? Не нужно решение такой ценой, даже если оно 100% корректно. Использование итераторов полностью разрывает порог сложности. И цена решения непомерна. :)Был бы умный человек, а о чем с ним поговорить - я найду, не переживайте :) Потому что на целом форуме желающих почти не осталось. :) |