ch
Feedback
Бестиарий программирования

Бестиарий программирования

前往频道在 Telegram

Наблюдения за жизнью ошибок в коде. Андрей Карпов. ГОСТ Р 71207-2024, ГОСТ Р 56939-2024, РБПО, Статический анализ кода Канал-дублёр в MAX: https://max.ru/join/3VWTp9apkQvTMSRQ__LGiTQ5NGVBj8p_tOpwlQO6vS8

显示更多
1 141
订阅者
无数据24 小时
+17
+2830
帖子存档
В этот чудесный летний день мы предлагаем вам сделать коллаборацию! 🔥 А какие варианты взаимодействия есть и куда писать — м
В этот чудесный летний день мы предлагаем вам сделать коллаборацию! 🔥 А какие варианты взаимодействия есть и куда писать — можно узнать по ссылке 🔗 #PVS_Studio #статья

Статический анализатор — мощный, но не всегда простой инструмент. Поэтому мы подготовили для вас курс "Статический анализатор
Статический анализатор — мощный, но не всегда простой инструмент. Поэтому мы подготовили для вас курс "Статический анализатор PVS-Studio на практике"! Что вас ждет: - Вы узнаете возможности анализатора, актуальные требования ГОСТ и как устроено лицензирование PVS-Studio. - Познакомитесь с локальной работой с PVS-Studio в плагине для IDE. - Поймёте, как встроить PVS-Studio в рабочий процесс разработки и минимизировать ручную работу. - Узнаете про использование PVS-Studio в роли SAST-инструмента для автоматического поиска ошибок и потенциальных уязвимостей в исходном коде. - Разберётесь с системой мониторинга компиляции и разметкой предупреждений по стандартам MISRA на практике. Подробнее о курсе по этой ссылке 🔗 P.s. курс абсолютно бесплатный 😉

Ошибка, которую никто никогда не совершал. Ведь так, да? Уже с первого курса университета — или даже раньше — вы могли догада
Ошибка, которую никто никогда не совершал. Ведь так, да?
Уже с первого курса университета — или даже раньше — вы могли догадаться, что писать arr[len(arr)] — плохая затея. И вряд ли так кто-то может ошибиться, правда? Мы тоже так думали, пока не проверили 1000 проектов.

Хорошая новость для разработчиков на Unreal Engine: мы сделали PVS-Studio доступнее, и теперь анализ UE-проектов в PVS-Studio
Хорошая новость для разработчиков на Unreal Engine: мы сделали PVS-Studio доступнее, и теперь анализ UE-проектов в PVS-Studio доступен в лицензии Team, а не только в Enterprise. Подробности. Если вы работаете с Unreal Engine и давно присматривались к PVS-Studio, то сейчас самое время попробовать анализатор на своём проекте. А если возникнут вопросы по интеграции или настройке, наша команда поддержки всегда поможет вам разобраться.

kstrncmp uint64_t kstrncmp(char *str1, char *str2, uint64_t len){ uint64_t index_str = 0; uint64_t different_char = 0; while
kstrncmp
uint64_t kstrncmp(char *str1, char *str2, uint64_t len){
    uint64_t index_str = 0;
    uint64_t different_char = 0;
    while (index_str < len) {
        if (str1[index_str] != str2[index_str]) {
            different_char++;
        }
        index_str++;
    }
    return different_char;
}

Кажется я превратился в тролля. Но автор заслужил :) Мой комментарий к статье "Операционная Система на C без знаний C". Я так понимаю, речь идёт об этом проекте OS. Мдя. Ну что же, автору предстоит узнать ещё много о языке С. Например, что такое выход за границу буфера.
void terminal_write_hex(uint64_t hex_num) {
    uint64_t index_buffer = 0;
    char buffer[sizeof(uint64_t)];
    if (hex_num == 0x0) {
        terminal_write("0x0");
        return;
    }
    terminal_write("0x");
    while (hex_num > 0) {
        uint64_t digit = hex_num % 16;
        if (digit >= 10) {
            digit = digit - 10;
            buffer[index_buffer] = 'A'+digit;
        }else {
            buffer[index_buffer] = '0' + digit;
        }
        hex_num = hex_num / 16;
        index_buffer++;
    }
Какой милый баг. Посмотрите на размер буфера: не учитывается, что один байт превращается в два символа. Интересные времена "безопасного ПО" настают. Простите за едкость комментария, но не удержался, увидев проект автора:
Safe Life System Наш проект — это платформа для обеспечения и сохранения безопасности информации в цифровой среде, а также для развития независимой IT-экосистемы. Мы создаём комплекс программного обеспечения, ориентированный на защиту данных, открытость технологий и поддержку русскоязычного IT-сообщества.

Repost from СВД ВС
Современная разработка начинается с правильных инструментов. Завершился курс «Инструментальные средства ЗОСРВ «Нейтрино». Слу
+2
Современная разработка начинается с правильных инструментов. Завершился курс «Инструментальные средства ЗОСРВ «Нейтрино». Слушатели познакомились с инструментами разработки, отладки, анализа и верификации ПО для Нейтрино. Особое внимание было уделено работе с комплектом разработчика, его интеграции со статического анализатора PVS-Studio, системой сборки, а также инструментами анализа системных событий. Это позволило участникам познакомиться с современными подходами к повышению качества и надёжности программного обеспечения. Все участники успешно прошли тестирование и получили удостоверения о повышении квалификации. Обучение продолжается. Следите за анонсами новых наборов и выбирайте курс, который поможет решить ваши профессиональные задачи. #Курсы

Я сижу со взглядом на две тысячи ярдов после прочтения статьи "Манифест программиста, использующего AI-кодинг-агента". Как го
Я сижу со взглядом на две тысячи ярдов после прочтения статьи "Манифест программиста, использующего AI-кодинг-агента". Как говорится, то ли смеяться, то ли плакать. Ну на смех в паре мест меня пробило. К самой статье претензий нет: я потрясён тем, что вообще у кого-то возникла потребность в написании этого манифеста. Как быстро где-то в индустрии уровень разработки прошёл путь от обсуждения книг про написание качественного кода до режима "голова для того, чтобы туда кушать". Я пока сомневаюсь, что настолько всё плохо. Надеюсь, автор преувеличивает и иронизирует. А если нет? О, мой Дейкстра!
Появился тикет. Программист копирует ссылку, передает ее AI-кодинг-агенту и через какое-то время получает готовый Pull Request. ... Перед изменением кода программист должен воспроизвести баг, понять условия его появления и увидеть фактический результат.
Скажите, что я сплю. Если вайб-программист просто впихивает задачу, не воспроизводя баг, не разбираясь в сути и не проверяя результат правок... это вообще что?
Если программист не запустил продукт и не проверил результат, задача не закончена. Если программист просто передал тикет AI, а потом передал его код ревьюеру и тестировщику, он не выполнил свою работу. Он просто переложил ее на следующих людей.
База. Но ведь автор это всё написал зачем-то, а в комментариях всерьёз идёт обсуждение. Прошу прочитать эту статью, она небольшая. Интересно услышать ваши впечатления, мнения и комментарии. Хочется вынести из всего этого происходящего сюрреализма какие-то полезные выводы.

Я сижу со взглядом на две тысячи ярдов после прочтения статьи "Манифест программиста, использующего AI-кодинг-агента". Как го
Я сижу со взглядом на две тысячи ярдов после прочтения статьи "Манифест программиста, использующего AI-кодинг-агента". Как говорится, то ли смеяться, то ли плакать. Ну на смех в паре мест меня пробило. К самой статье претензий нет: я потрясён тем, что вообще у кого-то возникла потребность в написании этого манифеста. Как быстро где-то в индустрии уровень разработки прошёл путь от обсуждения книг про написание качественного кода до режима "голова для того, чтобы туда кушать". Я пока сомневаюсь, что настолько всё плохо. Надеюсь, автор преувеличивает и иронизирует. А если нет? О, мой Дейкстра!
Появился тикет. Программист копирует ссылку, передает ее AI-кодинг-агенту и через какое-то время получает готовый Pull Request. ... Перед изменением кода программист должен воспроизвести баг, понять условия его появления и увидеть фактический результат.
Скажите, что я сплю. Если вайб-программист просто впихивает задачу, не воспроизводя баг, не разбираясь в сути и не проверяя результат правок... это вообще что?
Если программист не запустил продукт и не проверил результат, задача не закончена. Если программист просто передал тикет AI, а потом передал его код ревьюеру и тестировщику, он не выполнил свою работу. Он просто переложил ее на следующих людей.
База. Но ведь автор это всё написал зачем-то, а в комментариях всерьёз идёт обсуждение. Прошу прочитать эту статью, она небольшая. Интересно услышать ваши впечатления, мнения и комментарии. Хочется вынести из всего этого происходящего сюрреализма какие-то полезные выводы.

Запись вебинара "Практическая интеграция PVS-Studio и SourceCraft" 🔥 В том числе будет про то, как ИИ помогает работать с пр
+1
Запись вебинара "Практическая интеграция PVS-Studio и SourceCraft" 🔥 В том числе будет про то, как ИИ помогает работать с предупреждениями анализатора. Получилась интересно, рекомендую познакомится с записью. Посмотреть можно тут: - VK Video - Rutube - YouTube - Наш сайт

Напоминаю заглянуть сегодня в 15:00 на вебинар про SourceCraft и посмотреть как мы с ним интегрируемся. SourceCraft — российская платформа для полного цикла разработки, тестирования и сопровождения программных продуктов. Она предоставляет разработчикам и IT-компаниям инструменты для хостинга кода (подобно GitHub), управления версиями, проведения код-ревью, сборки, автоматического тестирования и развёртывания приложений.

PVS-Studio теперь в GitVerse🔥 Мы добавили готовые шаблоны для статического анализа в GitVerse Starter Workflow (российский а
PVS-Studio теперь в GitVerse🔥 Мы добавили готовые шаблоны для статического анализа в GitVerse Starter Workflow (российский аналог GitHub/GitLab от «СберТеха»). Что это дает? Больше не нужно писать пайплайны с нуля. Теперь внедрить автоматическую проверку кода в CI/CD можно за пару минут. Как это работает: - При настройке workflow в GitVerse выбираете шаблон PVS-Studio под свой язык: C++, C# или Java. - В шаблоне уже прописаны базовые этапы сборки и анализа. - Слегка адаптируете настройки под свой проект — и готово!
"Каждый шаблон уже включает основные этапы сборки и статического анализа. После небольшой адаптации под особенности конкретного проекта пайплайн готов к использованию и может быть встроен в процесс CI/CD", — отмечает Валерий Филатов, Developer Advocate PVS-Studio.
Отличный способ сэкономить время на настройке инфраструктуры и повысить надежность кода 👍 Для пользователей GitVerse сделали специальный промокод. Пользуйтесь PVS-Studio 30 дней без ограничений: https://pvs-studio.ru/gitverse #PVS_Studio #GitVerse

Пометка в блокноте – Не забывать писать, сколько лет PVS-Studio на рынке Услышал на Физнес-Фест в докладе Игоря Манна мысль,
Пометка в блокноте – Не забывать писать, сколько лет PVS-Studio на рынке Услышал на Физнес-Фест в докладе Игоря Манна мысль, что не стоит забывать упоминать в разных местах, как давно вы на рынке. Это автоматически добавляет пару очков доверия. И действительно! "PVS-Studio — более 18 лет на рынке РФ" звучит солидно! В числах: Компания ООО "ПВС" (ранее "СиПроВер", переименована в "ПВС" в 2020 году) зарегистрирована 21 марта 2008 года. В этом году отметили совершеннолетие – 18 лет! Нашему продукту, который изначально назывался Viva64, тоже более 18 лет. Уже под названием PVS-Studio он был зарегистрирован 30 октября 2009 года. P.S. Кто угадал отсылку на картинке? Великий герой — Коэн-варвар из книг о Плоском Мире.

ИИ-кладенец Вспомнилась мне давеча книга "Исторические корни волшебной сказки" Владимира Яковлевича Проппа. Это монументально
ИИ-кладенец Вспомнилась мне давеча книга "Исторические корни волшебной сказки" Владимира Яковлевича Проппа. Это монументальное исследование сказок: как они зарождались, трансформировались, что в них означают разные сущности и т. д. Не берусь рекомендовать, так как литература специфичная, и я с ней знакомился из желания размять мозг непривычным. Вспомнилась она мне из-за воодушевления авторов статей, что вот ещё чуть-чуть и ИИ всё сделает за нас и "скрипач не нужен" (c). Я вдруг увидел связь между "ИИ сделает сам" и темой волшебных предметов и помощников, которую подробно разбирает Пропп.
Рассмотрение волшебного помощника облегчает и подготовляет рассмотрение волшебного предмета. Между ними существует теснейшее родство. Легко заметить, что эти предметы представляют собой лишь частный случай помощника. Помощники, живые существа и волшебные предметы, принципиально функционируют совершенно одинаково. Так, конь переносит героя за тридевять земель, но то же достигается при помощи ковра-самолета или сапог-самоходов. Конь побивает рать, но и дубина сама бьет врагов и даже берет их в плен и т. д.
Пропп подмечает феномен сознания: начиная использовать орудия труда, человек приписывает им самостоятельное действие. Вспомните сказки. Главный герой ведь на самом деле почти ничего не делает, всё за него исполняют помощники (ловят кого-то, строят хрустальный мост за ночь) или проблема сама решается с помощью какого-то магического предмета. В общем-то, герою достаточно взмахнуть неким мечом-кладенцом и дело готово. Думаю, вы поняли, к чему я клоню. Сейчас всё теми же волшебными свойствами наделяют ИИ-технологии и ожидают от них чудесного решения проблем без усилий. Это — новый волшебный помощник. Вроде все понимают, что ИИ — это инструмент, которым надо уметь пользоваться: что есть сложности и проблемы; что он помогает, но не заменят труд. По-серьёзному никто не говорит, что ИИ — это магия, но почему-то многие продолжают преподносить ИИ или воспринимать его как дубину, которая сама бьет врагов. Хотя для этого на практике нужна крепкая рука и физическая работа. Но нет, подавай "трах-тибидох".
Человек в меньшей степени замечает свое усилие и в большей — работу орудия. Так получается концепция, что орудие работает не в силу прилагаемых усилий (чем совершеннее орудие, тем меньше усилия), а в силу присущих ему волшебных свойств. Получается представление об орудии, работающем без человека, за человека. Орудие теперь обожествляется.
Вывода нет. Подметил интересное проявление мало осознаваемых психологических паттернов использования новых технологий/орудий труда. Сейчас, конечно, знания создаются на порядок быстрее, и разум более гибок и быстрее переучивается, но всё же какое-то прежнее, древнее восприятие мира влияет на нас, просвечивая сквозь слой образования и культуры.

Короче и быстрей (часть №5 из 5) – Замер скорости работы и заключение Давайте проверим замерами, как оно будет на самом деле в реальности. Пришлось немного заморочиться с тестами. Во-первых, надо было подавать такие данные, чтобы не возникало переполнение знаковых 64-битных переменных, так как это UB и замерам не будет доверия. Во-вторых, для честности, надо чередовать данные с нулём и без. В-третьих, цепочки входных данных должны быть разной длины. Не утверждаю, что измерения выверены, но общее представление они дают. Скорость работы первого изначального алгоритма взята за единицу отсчёта. Использовал Clang с ключом -O2. 1.      Изначальный вариант c двумя циклами: 1. 2.      Мой вариант одним циклом: 0.88. 3.      Вариант, подсказанный Claude, с одним умножением: 0.92. Рефакторинг дал ускорение в среднем на 10 %. Я ждал, что будет побольше, в районе 20—30 %. Но 10 % — это тоже хорошо, учитывая, что они достигнуты упрощением, а не усложнением кода. Заключение На этом разбор кода и его рефакторинг закончен. Был ли в этом смысл? С точки зрения улучшения конкретно этого кода – нет. Это сгенерированные тесты. Некритично, что код длиннее и медленнее, чем он может быть. С образовательной точки зрения – да. Неважно, создаётся код человеком или генерируется с помощью ИИ. Нужны эксперты, которые могут отличить хороший код от плохого. Быстрый он или нет. Безопасный он или нет. Кому-то достаточно, что код работает, и неважно, что там. В некоторых случаях, например для прототипа, это нормально. Однако те, кто не интересуется архитектурой, оптимизацией, безопасностью, скорее всего, просто не видят и не понимают картину разработки и сопровождения больших программных продуктов. Нас ещё ждут новости о маленьких и больших провалах таких проектов. ИИ — это мощный инструмент, но не волшебная палочка. Когда Claude подсказал мне альтернативный вариант алгоритма, это хороший пример, что ИИ можно использовать для исследований и усиления возможностей человека. Но точно также он легко нанесёт вред при бездумном использовании.

Короче и быстрей (часть №4 из 5) – Альтернативный подход Есть какой-то другой альтернативный подход? Есть. Не знаю, догадался ли я до него сам или нет. К сожалению, после написанию своего варианта кода, я поспешил поспрашивать, какие варианты могут предложить ИИ. Варианты от DeepSeek были не лучше, а некоторые даже хуже исходного. Например, он сократил одну из реализаций кода ценой переворачивания массива.
// Разворачиваем strides обратно
std::reverse(strides.begin(), strides.end());
А вот одна из альтернативных реализаций от Claude Opus заслуживает внимания. Он обратил внимание, что можно выполнять не две, а одну последовательность умножений! Если все элементы входного массива не нулевые, то по завершению цикла acc == ne. А если хотя бы один элемент был нулевой, то в конце можно просто поменять значение ne на ноль. Происходит вновь возвращение к флагу any_zero, но в более умном варианте. Используя эту идею, можно написать следующий код:
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  auto q = sizes.size();
  std::vector<int64_t> strides(q);
  int64_t acc = 1;
  bool any_zero = false;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--q] = acc;
    acc *= (sz == 0 ? 1 : sz);
    any_zero |= sz == 0;
  }
  const int64_t ne = any_zero ? 0 : acc;
  ....
}
Ассемблерный код:
.LBB1_7:
        mov     rdx, rsi
        mov     rsi, qword ptr [r13 - 8]
        add     r13, -8
        mov     qword ptr [rcx], rdx
        test    rsi, rsi
        sete    dil
        cmp     rsi, 1
        adc     rsi, 0
        imul    rsi, rdx
        or      al, dil
        add     rcx, -8
        cmp     r13, rbp
        jne     .LBB1_7
        xor     r13d, r13d
        test    al, 1
        cmove   r13, rsi
        mov     r14, r8
Будет ли код, в котором выполняется в два раза меньше умножений, более быстрым? Моё предсказание – необязательно. Процессор может выполнить два невзаимосвязанных умножения одновременно на разных конвейерах. Я делаю ставку, что мой вариант и вариант от Claude будут работать с практически одинаковой скоростью.

Короче и быстрей (часть №3 из 5) – Объединяем циклы - Заглянем в ассемблерный код Текст функции стал короче, но скажется ли это положительно на производительности? Да. Посмотрим на основной фрагмент ассемблерного кода для изначального варианта функции. Используется Clang с ключом -O2.
.LBB1_7:
        mov     rax, rsi
        mov     qword ptr [rbx + 8*r12 - 16], rsi
        mov     rsi, qword ptr [r13 + 8*r12 - 16]
        cmp     rsi, 1
        adc     rsi, 0
        imul    rsi, rax
        dec     r12
        cmp     r12, 1
        ja      .LBB1_7
        mov     r12d, 1
        cmp     rbp, r13
        je      .LBB1_9
.LBB1_4:
        mov     rax, qword ptr [r13]
        test    rax, rax
        je      .LBB1_5
        imul    r12, rax
        add     r13, 8
        cmp     r13, rbp
        jne     .LBB1_4
        jmp     .LBB1_9
Достаточно многословный ассемблерный код с двумя циклами. Теперь посмотрим, что сгенерировано для последнего сокращённого кода.
.LBB1_10:
        mov     rcx, rsi
        mov     rdx, qword ptr [rbp - 8]
        add     rbp, -8
        mov     qword ptr [rax], rsi
        cmp     rdx, 1
        mov     rsi, rdx
        adc     rsi, 0
        imul    rsi, rcx
        imul    r12, rdx
        add     rax, -8
        cmp     rbp, r13
        jne     .LBB1_10
Красивое. Один цикл. Коротко и быстро.

Короче и быстрей (часть №3 из 5) – Объединяем циклы Взглянем целиком на вариант кода, который получился к текущему моменту. s
Короче и быстрей (часть №3 из 5) – Объединяем циклы Взглянем целиком на вариант кода, который получился к текущему моменту.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  size_t i = nd;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--i] = acc;
    acc *= (sz == 0 ? 1 : sz);
  }
   int64_t ne = 1;
 
  for (auto s : sizes) {
    ne *= s;
    if (ns == 0) {
      break;
    }
  }
  ....
}
Теперь, когда кода меньше, становится очевидным, что второй цикл избыточен. В первом цикле мы перебираем все элементы. Так почему бы их сразу не перемножить?
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  size_t i = nd;
  int64_t ne = 1;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--i] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  ....
}
Красота. Мы перемножаем все элементы, несмотря на то, что один из них может оказаться нулевым? Нестрашно. Микропроцессоры сейчас быстро умножают. Можно потерять больше на повторном доступе ко всем элементам во втором цикле. Что ещё осталось? Не требуется изначально обнулять контейнер strides нулями. Всё равно все его элементы будут перезаписаны.
std::vector<int64_t> strides(nd, 0); // надо убрать второй аргумент
В принципе, мы закончили. Но можно сделать ещё одно косметическое изменение, избавившись от переменной nd. Она ни здесь, ни в последующем коде не нужна. Итоговый код:
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  auto q = sizes.size();
  std::vector<int64_t> strides(q);
  int64_t acc = 1;
  int64_t ne = 1;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--q] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  ....
}
Код сократился в два раза: с 20 до 9 строк! P.S. Если захотите и напишите комментарий, я приведу ассемблерный код, чтобы показать как он сократился и оптимизировался.

Короче и быстрей (часть №2 из 5) – Первый цикл Теперь вернёмся к началу функции.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
    strides[static_cast<std::size_t>(i)] = acc;
    const auto sz = sizes[static_cast<std::size_t>(i)];
    acc *= (sz == 0 ? 1 : sz);
  }
Из-за static_cast код выглядит тяжеловесным. Первое приведение типа нужно, чтобы какие-то компиляторы/статические анализаторы не ругались на странные арифметические игры.
std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1;
Рассмотрим, что будет, если убрать static_cast, а входной массив окажется пустым: 1. Если массив пуст, то nd = 0; 2. Вычтя единицу из беззнакового нуля, мы получим SIZE_MAX, т.е. очень большое положительное беззнаковое число. 3. Значение SIZE_MAX типа size_t неявно преобразуется в тип ptrdiff_t и записывается в переменную i. Получается, что i = -1, как и было задумано. Но вот тут как раз могут быть выданы предупреждения. Ведь мы инициализируем ptrdiff_t числом, которое больше диапазона максимально вмещаемого числа. Поведение в такой ситуации до C++20 определяется реализацией – implementation defined behavior. После C++20 поведение определено. Итого: первый static_cast лучше оставить на месте. Про остальные такого сказать нельзя. В них нет никакого смысла. Оператор [] в классе vector принимает аргумент типа size_type (этот тип является синонимом size_t). Значение переменной i автоматически будет преобразовано в size_t, и в этом нет чего-то странного, опасного или подозрительного. Явное приведение типов только загромождает код, и от него лучше избавиться.
for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
  strides[i] = acc;
  const auto sz = sizes[i];
  acc *= (sz == 0 ? 1 : sz);
}
Первый шаг сделан. Можно теперь всё-таки упростить длинную строку с циклом? Давайте подумаем. Хочется написать как-то так:
for (auto sz : std::ranges::views::reverse(sizes)) {
  strides[???? i ????] = acc;
  acc *= (sz == 0 ? 1 : sz);
}
Всё равно требуется переменная i для обхода массива strides, начиная с конца. Так что совсем упростить код и избавиться от i не получается. Поэтому сделаем так:
int64_t acc = 1;
size_t i = nd;
for (auto sz : std::ranges::views::reverse(sizes)) {
  strides[--i] = acc;
  acc *= (sz == 0 ? 1 : sz);
}
Если честно, мне не нравится, что из-за использования --i код стал сложнее. Теперь требуется вникнуть, почему переменная в начале уменьшается, а уже затем используется для обращения к элементу массива. С другой стороны, кода стало меньше и его можно быстрее просмотреть глазами. Так что, наверное, когнитивная сложность кода осталась в итоге такой же. Т.е. понимать код стало не проще, но и не сложнее. В любом случае код стал покороче, так что ok.

Короче и быстрей (часть №1 из 5) – Второй цикл Попалась функция на языке С++. На её примере прям просится показать, что, делая рефакторинг, можно не только эстетично сократить код, но и оптимизировать его. Давайте разомнём мозги, они нам ещё пригодятся, несмотря на эпоху вайб-кодинга. Кто-то ведь должен понимать, как делать надо, а как не надо. Приведённый ниже код я встретил в вайб-код проекте VibeTensor. Я исследую подобные проекты в качестве натуралиста. Мне интересен генезис новых видов дефектов и недостатков в коде. Одно из наблюдений – генерированный код более "пухлый", что затрудняет его восприятие человеком и оптимизацию компиляторами. Следующий фрагмент кода как раз это хорошо демонстрирует.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
    strides[static_cast<std::size_t>(i)] = acc;
    const auto sz = sizes[static_cast<std::size_t>(i)];
    acc *= (sz == 0 ? 1 : sz);
  }
 
  int64_t ne = 1;
  bool any_zero = false;
  for (auto s : sizes) {
    if (s == 0) {
      any_zero = true;
      break;
    }
    ne *= s;
  }
  if (any_zero) {
    ne = 0;
  }
  ....
}
С одной стороны, размер и скорость этого кода некритичны, так как он относится к тестам. Однако этот код размножен по 9 файлам. Оставим за скобками, что такого по-хорошему вообще быть не должно. Но раз код размножается почкованием, желательно чтобы он был бы тогда по возможности компактным. А ещё важно, что генерируется С++ код, и он обязан быть оптимальным. Само назначение языка – высокоэффективные приложения. В рассматриваемом месте – это просто медленный тест. Но в другом месте что-то подобное приведёт к существенному замедлению приложения. Или скажется кумулятивный эффект множества неудачных фрагментов сгенерированного кода. Медленный С++ код – это противоестественно. Поэтому по-прежнему полезно развивать свою экспертность в понимании, удачным ли получился код и как его можно улучшить, сократить, оптимизировать. Или сгенерировать снова, используя уточнения. В общем давайте потренируемся и проведём рефакторинг. Начнём с этого фрагмента:
int64_t ne = 1;
bool any_zero = false;
for (auto s : sizes) {
  if (s == 0) {
    any_zero = true;
    break;
  }
  ne *= s;
}
if (any_zero) {
  ne = 0;
}
Здесь перемножаются все элементы массива. Если встретится 0, то цикл прервётся, чтобы зря не обрабатывать оставшиеся элементы массива. Всё равно ведь ноль получится. Чтобы обнулить переменную, где хранится произведение, используется флаг any_zero`. Этот подход избыточен, можно проще.
int64_t ne = 1;
for (auto s : sizes) {
  if (s == 0) {
    ne = 0;
    break;
  }
  ne *= s;
}
Когда встретится 0, обнулятся ne и цикл завершится. Можно продолжить упрощение. Современные процессоры быстро выполняют операции умножения. Поэтому можно в начале перемножить, а потом уже проверить.
int64_t ne = 1;
for (auto s : sizes) {
  ne *= s;
  if (ns == 0) {
    break;
  }
}
Функциональность кода не изменилась, но он стал короче и, на мой взгляд, даже понятнее.