Как стать автором
Обновить

Комментарии 563

Переходите на C++Builder))

Но но.. Попрошу птичку нашу не обижать. Некоторые с него и не уходили))

Эх! Если бы на нём работали либы от Visual C++, то я бы с C++ Buiilder и не уходил никуда. Но, увы, нужная либа часто под Visual C++, а C++ Buiilder не поддерживается. :-(

Я всегда руками перехреначивал такие либы под билдер.

Простите, а это в каком году написано? Наезжать на инклюды и SFINAE после выхода C++20 странно. Я понимаю, что не все проекты могут себе позволить перейти на него, сам на 17м сижу, но это же не претензия к развитию языка.

Расширения обсуждались, только не в таком виде, а как унифицированный синтаксис вызова функций и методов, когда this уходит первым аргументом, как в D, но не пошло, а жаль.

Ну а properties бесплатные только когда инлайнятся, а если хочется бинарной совместимости, то нужен честный вызов метода, что не так уж дёшево.

Согласен, мой косяк в том что я не разобрался в концептах... если это решает проблему SFINAE, то с темой явно стоит ознакомиться не по-диагонали. Все же отмечу что SFINAE был, и остается с нами надолго. А такой класс решений, на мой взгляд, должен зарубаться еще на уровне идеи. Тем не менее это попало в стандарт.

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

SFINAE никуда не денется, он всё ещё используется и работает. Концепты не полностью заменяют, а решают 90% задач коротко и просто. Точно так же constexpr не решает все задачи шаблонов, только выделяет популярное подмножество и предлагает понятный способ решения.

Какие задачи решает SFINAE, но не решают концепты?

Не то чтобы совсем не решает, но лучше выглядит для тех, для которых SFINAE изначально придумывали. То есть простой разбор перегрузок без замороченных отличий по особенностям типов и enable_if. Например, перегрузки функции, обрабатывающей список значений, vector и map шаблонного типа. Гораздо проще написать 3 шаблонных функции-перегрузки с list, vector и map в сигнатуре, чем писать концепт is_list, is_vector, is_map.

А вот все использования enable_if и подобного уровня хаки концепты однозначно решают лучше.

Шаблонизация вместо перегрузок это частая практика, к сожалению.

У шаблонизации внутри может быть и enable if, и другие SFINAE техники, и концепты, и даже if constexpr, последнее особенно плохо читается, как по мне.

Мой поинт — всё, что раньше решалось через SFINAE сейчас можно решить через concept/requires. Не знаю контрпримеров.

Вы не любите кошек? Вы просто не умеете их готовить.

по поводу setter/getter который автор пытается использовать для работу с элементами вектора -вообще-то есть перегрузка операторов, которая в вашем конкретном примере сократит синтаксис.

Пользоваться или нет -решать вам.

Опять же чтобы инклуды не просились каждый раз, давно придумано

If defined module_included …

Это вроде азбука объявлений header файлов в С/С++.

Предположу, что речь была не про include guard (это само собой), а про парсенье инклудов в разных файлах в одном проекте. Если без precompiled headers, то одно и то же разбирается и компилируется снова и снова.

Недавно экспериментировал с precompiled headers в MSVC 2022 и пришёл к выводу что не зря их теперь там по умолчанию отключили. Сейчас студия предкомпилирует всё подряд и довольно неплохо отслеживает что и когда нужно перекомпилировать, а что нет. Ускорения от включения precompiled headers не заметил.

Заметил сильное замедление от закольцованных взаимных ссылок в заголовочных файлах. Оно иногда проявляется логическими ошибками, но не всегда. Зато явно увеличивает время компиляции и размер ipch файлов.

сорри, не понял про setter/getter для вектора... setter/getter у меня упоминается в пропертях, которые удобно их заворачивают, это не только к векторам и контейнерам относится, а ко всему

с инклюдами проблема в том что их все равно надо делать, а для уменьшения инклюдов все равно нужно писать forward declaration'ы. Это все тупая работа по решению зависимостей, которую в других языках перекладывают на кмпилятор

НЛО прилетело и опубликовало эту надпись здесь

IMHO, чтобы пользоваться свежими фичами плюсов, нужно слишком много понимать даже не в языке, а в том, как это всё готовить.

На нашем небольшом open-source проекте код собирается внутри os, которую предоставляет вендор: raspberry pi OS, ubuntu для Jetson, debian для radxa. И там нафига не последние версии gcc или cmake.

Да, по хорошему надо самому собрать тулчеин со свежим компилятором и остальным - но это же реально хардкор, когда на сборку кода надо тратить столько же усилий, сколько на его написание

а какие альтернативы то на этих же платформах?

Если говорить про "как использовать свежий компилятор для debian в "полу-embedded" - то только собирать свой тулчейн для кросс компиляции. Или собирать свежий компилятор на самой sbc.

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

не, я про альтернативу плюсам, в сборке тулчейна особо то проблем нет, crosstool-ng с этим очень сильно помогает.

Я всё хочу раст попробовать, как бы попсово это не звучало.

С другой стороны, я умею писать быстрый код и на шарпах, так что ещё не скоро до раста дойду

Либо обрамлять старый код как статические либы, либо писать свою систему сборки, третьего не дано

Согласен, статья старая

Поставил плюс автору за старательность и минус за саму статью. Все, что вы написали неверно из-за одного момента. Вы не правильно понимаете:

Ты не платишь за то, чего не используешь
Если действительно разобраться, то это не совсем правда. Я не спорю, используя С++ ты довольно приближен к железу и накладные ресурсы довольно маленькие. Но они есть, от этого никуда не деться. В итоге разработчик вводится в некое заблуждение этой красивой фразой.

Это следует понимать, не как "накладные расходы на RTTI довольно маленькие, но они есть, от этого никуда не деться", а "если вам не требуется RTTI, то опция -fno-rtti полностью убирает даже минимальные накладные расходы и ненужный вам функционал".

Поэтому все остальные проблемы, которые вы перечислили в статье, не принципиальные и требуются только для обеспечения обратной совместимости кода (а не стандарта). Для того, чтобы легаси код можно было собрать новой версией компилятора, и все продолжало работало как и раньше.

А если вам не нужны или не нравятся какие-то возможности, ну так и не используйте их. Ведь "Ты не платишь за то, чего не используешь" :-)

НЛО прилетело и опубликовало эту надпись здесь

Стандрарт подразумевает возможность откючения RTTI, а по какой опции, это делали реализации контретного компилятора, со всеми остальными прдложениями идите в комитет по стандартизации :-)

Я не плюсовый разработчик, выскажу мысль со стороны.

В каких областях сейчас популярен С++ и какие у него в них были конкуренты в последние годы?
Мне вспоминаются такие:

  • Геймдев. Тут из конкурентов вроде только С# + Unity, и даже сам Unity частично вроде бы на С++. Конкурентов С++ почти нет, особенно для игровых движков.

  • Интерфейсы высокопроизводительных десктопных приложений. То что осталось на С++: браузеры, редакторы фото и видео с огромным циклом разработки. Что-то переписывать слишком долго переписывать, что-то вроде браузеров особо и не на что. Недавно появился Rust, но число разработчиков на нём несопоставимо, наработок меньше.

  • HFT - конкурентов особо нет.

Итого. У С++ долго не было особых конкурентов в его нише компилируемых языков без сборщика мусора и zero-cost абстракций. У большинства других языков конкуренты были. У Java был С#, а затем ещё и другие языки внутри экосистемы JVM. У Python - PHP, Ruby. Даже у формально безальтернативного JS были компилируемые в него языки в качестве конкурентов. Ну Rust появился, но у него и близко пока нет экосистемы С++.

Любопытно посмотерь поменятся ли что-то лет через 5-10 после появления Rust, а также всяких Zig, Carbon и прочих Mojo.

Помимо этих трех есть еще огромная индустрия эмбеддед (машины, ракеты, мед оборудование, спутники и тд.). Вот там плюсы вряд ли будут вытеснены в обозримом будущем

Да, спасибо что напомнили. Я ещё СУБД забыл, и там конкурентов тоже не было.

В эмбеддед в основном пишут на обычном Си.

Смотря в каком, эмбеддед очень разный бывает. Под bare metal - да, под RTOS - я бы сказал уже 50/50, а под Embedded Linux C++ встречается повсеместно.

Я вот под голое железо на С++ пишу. И постоянно его... ругаю тихими словами (но чистый Це ещё хуже: те же самые проблемы, только ещё и функционал убогий).

Все-ж уже больше на ++. На старые контроллеры - да, на C в основном.

Ну там часто смесь. Какие-то фичи из плюсов используются часто.

Rust ?....

Интерфейсы высокопроизводительных десктопных приложений.

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

Сам интерфейс можно и на Питоне наваять, там скорость работы не требуется, главное скорость разработки и простота поддержка реализации.

Вообще я имел в виду всякие Photoshop, Blender, AutoCad, 3Ds Max, Adobe Premier.

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

И при этом на питоне это будет один поток, следовательно еще и тормоза )

Биткоин с 2013 майнят только на асиках, потому что видюхи проигрывают им на порядки по производительности и энергоэффективности. Что ни говори, а C++ развивается быстрее хотя бы «биткоин-критиков», уже неплохо!

Конкурентов С++ почти нет, особенно для игровых движков.

Но авторы игр в большинстве своём пишут не игровой движок, а игровую логику для этого движка ;-) В тех же играх на Unity основной язык разработки именно С#

Большинство крупных игр пишется либо на внутреннем движке либо на анриле которые поголовно на С++ юнити удел Индии и маленьких проектов, за рядом исключений

Ну, вроде как, 7 проходный, а болячки когда объекты ссылаются друг на друга лечить никто не собирается, мол, колхозьте форварды как последние 40 лет

НЛО прилетело и опубликовало эту надпись здесь

А в чём проблема не использовать темплейты, раз вам они не подходят?

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

НЛО прилетело и опубликовало эту надпись здесь

Любопытно посмотерь поменятся ли что-то лет через 5-10 после появления Rust

<...> первая стабильная версия (1.0) вышла 15 мая 2015 года <...> (Вики).
То есть ему уже 9 лет.

Первая стабильная версия Golang вышла в 2009, но никто на нём всерьёз не писал до примерно 2015г. Версия 1.0 у Python — 1994.

Субьективно с очень хорошим пиаром как у Golang и C на языке начинают массово писать в прод лет так через 4-5. А обычно — лет через 8-10.

Первая стабильная версия Golang вышла в 2009, но никто на нём всерьёз не писал до примерно 2015г.

В 2009-ом Гугл просто предъявил Golang миру, релиз версии 1.0 у Golang-а состоялся в марте 2012-го.
Собственно, про Rust так же было известно задолго до релиза версии 1.0 в мае 2015-го.

Если верить Wikipedia, то Docker появился в 2013-ом, а в 2014-ом там заменили LXC на написанный на Go libcontainer:

Docker debuted to the public in Santa Clara at PyCon in 2013.[48] It was released as open-source in March 2013.[21] At the time, it used LXC as its default execution environment. One year later, with the release of version 0.9, Docker replaced LXC with its own component, libcontainer, which was written in the Go programming language.

Так что с "никто" и "всерьёз не" получается как с совой на глобус.

Ну и добавьте к дате релиза Go 1.0 девять лет и оцените насколько сильно он проник в мейнстрим к тому времени. И сравните с проникновением в этот же мейнстрим Rust-а на данный момент. Как раз 9 лет с релиза версии 1.0.

Тут смотря что считать мейнстримом. Например в области микроконтроллеров без библиотек вендоров (HAL) редко кто пишет. И пару лет назад они начали появляться на Rust.
Но кроме того на Rust есть стандартное API HAL (https://github.com/rust-embedded/embedded-hal), чего за все цать лет не удалось создать в других языках.

Фактически под все микроконтроллеры есть библиотеки на С, сильно меньше половины на С++, и сейчас примерно столько же на Rust. Я считаю что это уже мейнстрим.

По вашим критериям так ни C#, ни JavaScript до мейнстрима так и не добрались.

В микроконтроллерах конечно. Вероятно и не доберутся, т.к. сборщик мусора и рантайм.
Просто я считаю, что Rust лучше всего подходит для микроконтроллеров, ядра ОС и драйверов. Вобщем тех областей, где нет обычного рантайма, который дает ОС во многих других языках.
Кстати, в ядро Linux тоже Rust добавили, и на нем пишут новые драйвера. Так что в 1,5 из этих 3 областей уже мейнстрим. А обычные приложения под Linux, Windows или Android лучше писать на чем-нибудь со сборщиком мусора (имхо).

В микроконтроллерах конечно.

Прекрасно. Только к контексту разговора имеет опосредованное отношение.

Чтобы было лучше понятно, такая аналогия:

В конце 1990-х JavaScript был мейнстримом в нише Web-страничек. Но на всю разработку софта (вне зависимости от прикладных ниш) влияния не оказывал. Прошло двадцать лет и JavaScript мейнстрим из мейнстримов вне зависимости от ниши.

Может быть Rust стал мейнстримом в разработке для микроконтролеров. Прекрасно, если так.

Но вот вообще в разработке софта вообще разговоров о Rust гораздо больше, чем самого Rust-а. Не смотря на то, что релиз версии 1.0 состоялся девять лет назад.

Путь к настоящему мейнстриму у тех же C++, Java, C# и Go был гораздо короче.

А может вы просто не хотите оглянуться по сторонам?

Cloudflare целиком на Rust переписались, в исходниках Android его уже столько же, сколько C, AWS несколько сервисов целиком переписали и не останавливаются (и сделали Firecracker целиком на нем, опенсорс менеджер микровиртуалок, на котором работают Lambda и Fargate), с голенга многие тоже переписываются. Я могу дать полный список известных мне проектов, там от MESA до Figma, Vercel и части бэка npm.js репозитория. И под спутники пишут на нем, и новые проекты от мала до велика (от Tauri, который по сути Electron здорового человека, и Embassy, который embedded просто и быстро, до Western Digital, которые платформу обработки данных на 5 петабайт в день на нем пилят). Но возможности спрятать под спойлер я тут не вижу, а еще больше засорять коммент не хочется.

https://habr.com/ru/articles/813645/comments/#comment_26837079

"без сборщика мусора" - есть полумеры в виде ARC (obj-c, swift, vala). есть @nogc в D

Самое смешное в стандарте предполагался недосборщик мусора. Раньше. Его выкинули, т.к. ни один компилятор не смог это реализовать

Достаточно открыть vcpkg.io и ознакомиться с огромным количеством библиотек написанных на C/CPP, чтоб увидеть - 90% современной базы кода основана на указанных языках. Все остальные языки и фреймворк не переписывают ни одну базовую библиотеку но почти все в той или иной мере через биндинги и прочие приколы завязаны на них. Таким образом место CPP отнюдь не только в игровых движках/десктопах/ембедед. Это фундамент на котором строится если не все, то львиная доля остального.

ПС. Извините, сразу дополню коммент мнением по самой статье, раз уж начал ?.

Ну вы бы блин ещё к фортрану и коболу докопались по поводу синтаксиса/стиля итд. CPP занимает свою важную нишу и имеет преогромную кодовую базу(пример выше), вносить изменения в язык нужно крайне осторожно.

Долго хидеры компилятся? Ну дайте больше потоков, юзайте jom коли студийный nmake по сей день в одно ядро долбиться. Используйте cmake+ninja итд. Это вообще не проблема уже, а время разработчиков языка можно потратить на более важные проблемы.

Не читаемые ошибки и тупые классические IDE, так не проблема языка - это MS и Ко должны позаботиться.

Если среда разработки лагает - переходите на Qt Creator или VS Code и CMake, никаких лагов, кроссплатформенность, менеджмент зависимостей из vcpkg, простота и лёгкость из коробки.

Если сам язык не устраивает или не подходит под какую-то задачу, ну так возьмите другой язык - их вон наклепали гору куда лучше под конкретные задачи. Правда там любой поскреби - рано или поздно доскребешься до C/CPP или библиотек на них.

То как выглядят лямбды, итераторы, стандартная библиотека - ну вот так вот исторически сложилось, такова цена свободы и универсальности языка, да есть определенные нюансы. Ну так зато к примеру у вас лямбда это +/- обычный CPP объект (ну функтор), только безымянный и в compile time созданный компилятором, потому и синтаксис такой специфический.

Ну да надо лямбде перечислить что нужно захватить или просто захватить все, но где тут проблема то? Вы хотите чтоб решение принималось за вас? А как вы можете рассказать? Какой-то может есть универсальный или эвристический алгоритм который поймет что нужно а что нет? А это повлияет на рантайм или на компайлтайм?

Тут чего не коснись - может так в ответ по башке прилететь всему сообществу - десятилетиями аукаться будет. Многое из сказанного в статье это вкусовщина. Мне вот например нравится как многое сделано.

Уж пусть лучше CPP развивается медленно но предсказуемо. Вы смотрите вокруг на примеры. Питон с 2 на 3 версию сколько уже, 15 лет до конца никак не перейдет? До сих пор тянут лямку с питоном 2.7, все никак не закопают и в линуксе до сих пор жонглировать приходится чтоб то один то другой скрипт запустить то во 2 то в 3 питоне. А тоже были светлые идеи типа "давайте-ка за старое не будем цепляться". Надо оно в языке который вместе с C является базой для чуть не всего ИТ? Не думаю.

ППС: тем не менее спасибо за статью, было интересно, прошу прощения за излишнюю эмоциональность в изложении мнения/ответа ?. Предлагаю сконцентрироваться на плюсах которые вокруг языка появились и развиваются в верную сторону, типа стандартизации проектов с CMake/CMakePresets, с нормальными менеджерами зависимостей типа vcpkg/conan итд. Может сам язык и не сильно развивается, но инфраструктура вокруг него разительно улучшилась в последние 5 лет.

Есть что ответить на пару ваших тезисов.

Пишу на .NET. Понятно, что рантайм на плюсах, но пакетов/библиотек, которые опираются на нативные(сишные) либы - крайне мало. Ту же реализацию grpc майкрософт переписали на .Net.

По поводу инфраструктуры вокруг плюсов - да, развивается, но отстаёт лет на 10. Не так давно я писал маленькое тестовое приложение. К нему нужно было подключить две библиотеки. Одна из них была только в conan, другая только в vcpkg. Забил на всё на этапе заставить нормально работать vcpkg в студии.

Ну как бы что-то движется, но после других языков тулинг плюсов - боль и страдания

Отлично что появляются нативные версии библиотек под каждый язык. Будет работа у разработчиков, будут платить зарплату на поддержку данной реализации под конкретный язык.

Тем не менее, я не уверен что кодировщики (ffmpeg), архиваторы (любой хоть zlib), мат-либы (NumPy) и многи другие вообще хоть когда-то будут переписывать под какой-то иной язык. C и в куда меньшей мере CPP здесь вне конкуренции.

То что отсутствует библиотека в vcpkg, ну так мы же должны на дистанции смотреть с конкретными примерами. По vcpkg, когда они разобрались с базовой архитектурой своего пакетного менеджера (а там переделок хватало в первые три года), то они взяли норм темп на добавление новых либ. Вот здесь страница с релизами vcpkg, https://github.com/microsoft/vcpkg/releases, обратите внимание что в каждом релизе указано кол-во обновленных и добавленных библиотек.

Релизные срезы пошли каждый месяц и ежемесячно добавляется по 5-10-20 библиотек. А обновляется по 100-200. Это отличный уровень поддержки я уверен как от сообщества так и от множества коммерческих компаний. Пройдет немного времени и будет там все Вам необходимое.

Обратите внимание что порт не добавить и не обновить если не пройдет внутренний CI/CD на всех поддерживаемых платформах а также глубокий ревью - это указывает на очень хорошие контроль качества и регрессий.

Да даже свой порт сделать очень просто, в несколько строчек (если исходная либа на CMake), вот взгляните на пару моих примеров: https://github.com/microsoft/vcpkg/pull/34510

И на этом фоне давайте сравним термин "тулинг плюсов" 10 лет назад со сборкой всего самостоятельно километровыми скриптами/руками под нужный компилятор и сейчас с пакетными менеджерами. Ну и наконец - другие языки моложе, в них учтено множество ошибок, а многие из них и не компилируемые вовсе, там от пакетного менеджера требуется не собрать мудреную библиотеку с десятком зависимостей разными компиляторами под разные платформы, а тупо скачать несколько файлов и разложить по папочкам. Уровень сложности решаемых задач даже нельзя сопоставлять.

Ну короче, это все лирика, я просто за позитивный настрой =)

Вот честно, не понимаю ажиотажа вокруг Rust.

ИМХО, похоже на попытку выделиться, плюс создать язык для тех, кто "не осилил С++".
Вот какой был смысл придумывать для него такой корявый синтаксис, который ближе к ассемблеру, чем к ЯП "высокого" уровня?

Чтобы хоть в чем-то "порог вхождения" повысить, что ли?
Мол, "вот вам, гадкие С++ники, хрен легко перестроитесь".

НЛО прилетело и опубликовало эту надпись здесь

Я бы предложил DLang с включённым live

НЛО прилетело и опубликовало эту надпись здесь

Естественно С-подобный. Хотя бы потому, что на нем основано куда больше языков, и соотвественно, кода, чем на Rust-подобном.
И можно не впадать в демагогию, а-ля "Не существует людей, осиливших C++"?
Как написали ниже - "осилить c++ в мере, позволяющей написать +- адекватное большое приложение легче чем осилить ржавого ".
То, что кто-то не осознает без помощи компилятора, что такое многопоточность и асинхронность - это наверное его проблемы?

НЛО прилетело и опубликовало эту надпись здесь

а в проектах на других языках ошибки ни когда не совершают и все они отлавливаются на этапе запуска у программиста в ide, я правильно понял мысль?

НЛО прилетело и опубликовало эту надпись здесь

В моём коде на агде ошибок нет

С поправкой на то, что в типах выражено то, что нужно

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

Как говорится "это зависит". Тут недавно была статья про Rust в геймдеве, так автор очень сильно плакался о том, что т.к. Rust очень хочет выловить максимум возможных ошибок, то он требует делать слишком много телодвижений в случае некоторых изменений, когда программисту нужно "побыстрому запрототипировать".

Т.е. в тот момент когда "лучше возможно с ошибками, но быстренько попробовать", Rust говорит, типа "нет милок, ты захотел сделать вот так, тогда давай зарефактори мне половину кода, чтобы я был точно уверен что ты нигде не накосячил".

В той статье автор не понятно на что плачет. Всегда можно написать static mut переменную, и везде к ней обращаться через unsafe. Также можно всю обработку ошибок игнорировать, вызывая unwrap, для прототипа сойдет. Всё обвешать слабыми ссылками и т.д. Но он хочет писать на Rust как на Python, о чем ему в комментариях и написали.

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

Отнюдь, осилить С++ можно, я потратил 2 года свободного времени чтоб разобраться в почти всех тонкостях языка. Но есть нюанс, я вот понимаю что при передаче классической строки в функцию с аргументом типа char*& оно может быть ub на старых стандартах и наоборот материализоваться на новых, но я всё ещё junior с ЗП меньше 80К

А мог бы писать говнокод все эти 2 года и дослужиться до мидла с окладом в +150КК

ЗЫ я про код вида Do("hello"), где Do это void()(char*&)

чтоб разобраться в почти всех тонкостях языка

Прям разобраться? Вот прям читая произвольный код можете объяснить, как будет происходить (C)TAD? pointer provenance вам хорошо понятен? Да хотя бы даже категории значений?

А то я смотрю на комитет, там люди десятилетиями над языком работают, а потом принимают дефект-репорты о таких фундаментальных и, сравнительно, простых вещах как объектная модель, например.

Уу.. а как это откомпилилось? Должно быть `(const char*&) - не тот тип, это не UB. Это в сях можно было.

НЛО прилетело и опубликовало эту надпись здесь

Это круто конечно, но у меня на работе есть те кто уже и по 30 лет этим всем занимается и они знают С++ хуже меня. Опыт не показатель квалификации.

С опытом растёт лишь понимание как писать так чтоб тебе платили больше, и только) Остальное идёт на откуп саморазвитию.

НЛО прилетело и опубликовало эту надпись здесь

что то ты загнул конечно))

я на плюсах уже 10 год пишу, 2 из которых в статусе lead и вроде не плохо понимаю за многопоточку, SFINAE, макросы и кроссплатформенного кода пишу много, но даже я бы не стал зарекаться про "во всех тонкостях", почти на каждом докладе по C++ я всё ещё узнаю новые для себя вещи за что и люблю этот язык, он безграничен в своём познании

Сейчас(3 года как) выкатили корутины с концептами и вроде в общем оно конечно понятно зачем и как но я не готов прям сходу что то написать с их использованием.

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

Так что ты либо гений либо находишься на другом пике кривой Даннинга-Крюгера

Я сейчас работаю и у меня есть коллеги с большим опытом. Мне кажется разница в том что я изучаю язык просто ради веселья, а не для того что бы решать какие-то реальные задачи. Мне крайне весело разбираться в системе типов С++ и то как там это всё работает. Решать всякие задачки которые ломают мозг, просто ради того чтоб их решить. И в итоге я использую те же концепты-замыкания постоянно, ибо для меня это очевидная фича языка которая позволяет работать с типами более гибко, а для моего коллеги это лишь способ решить проблему с перегрузкой какой-то шаблонной функции.

И если честно, я жалею что потратил так много времени просто ради того чтоб только это и изучить. Я бы мог устроится куда-то как стажёр и получить больше опыта, больше знаний фреймворков, большую зарплату, а в итоге за эти +2 года только С++ и знаю.

Имхо, осилить c++ в мере, позволяющей написать +- адекватное большое приложение легче чем осилить ржавого :)

НЛО прилетело и опубликовало эту надпись здесь

Приглядитесь к borrow...

НЛО прилетело и опубликовало эту надпись здесь

Многие из идей раста близки современному C++. Небезопасные операции в которых легко совершить ошибку спрятаны в реализации, но в Rust значительно больше гарантий.

Но объем этих гарантий делает написание кода с супер высокими требованиями по производительности/задержке или с доступом к железу очень неудобным или невозможным без широкого использования unsafe. Вроде бы сообщество Rust планирует улучшить эргономику unsafe, но пока что некоторые вещи значительно удобнее делать на C++.

Так что Rust это конкурент C++ когда безопасность важнее производительности и конкурент языков со сборщиком мусора когда производительность важнее скорости разработки.

когда безопасность важнее производительности

Но ведь безопасность как минимум в значительной степени равна корректности работы. Отсюда вопрос: зачем вам быстрые некорректные программы?

Rust для обеспечения безопасности и отсутствия UB вводит ограничения, начиная от проверки индексов при доступе к элементам массивов, до необходимости использования Arc<Mutex<T>> в многопоточных приложениях.

В большинстве случаев эти ограничения не важны, или обходятся, но, например, многопоточный мутабельный доступ к памяти может быть необходим.

Безопасность памяти не гарантирует корректность. Кроме того распространенность языков с динамической типизацией показывает что скорость написания может быть важнее безопасности типов. Можно задать вопрос: зачем нужны быстро написанные некорректные программы?

НЛО прилетело и опубликовало эту надпись здесь

если кратко, нет, не равна.

 изменить стратегию компиляции? Решение буквально очевидно

расскажете "очевидное" решение? Стратегия компиляции из С проста и гениальна, у неё куча преимуществ. Я так понимаю автор предлагает какой то "глобальный неймспейс" в котором, видимо, весь С++ код мира собран, иначе откуда компилятор поймёт что там есть неизвестно

Проблемы со специализациями решаются элементарным правилом, не делать специализации хрен знает где в .cpp файле, а делать либо в том файле где объявлен тип, либо в том где объявлено то что специализируют

Нет, зачем весь код С++ мира, только локального проекта. Грубо говоря сначала все распарсить, собрать AST. Решить все зависимости. А потом уже генерить код. Можно представить это как некую аналогию precompiled header'а на весь проект и forward declaration всех типов

и откуда компилятор узнает кто у вас составляет "локальный проект"? А про хедеры подключаемые несколько раз что он скажет? Что будет с инкрементальной компиляцией? И почему вы при таком подходе не сделаете unity сборку, которая соберёт все .cpp в один файл?

НЛО прилетело и опубликовало эту надпись здесь

Система сборки про это расскажет.

эх если бы вы знали, что наоборот система сборки спрашивает компилятор что является зависимостями проекта. Иначе, например, поведение языка зависело бы от системы сборки, а не от компилятора

Ворнинг скажет, что модуль импортируется дважды, и второй импорт не нужен

а он нужен, не все хедеры pragma once, у них гораздо больше применений

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

и что же там? Ах да, скриптовые языки там, вот что. Либо всё очень плохо с инкрементальностью

Потому что тогда и инкрементальной компиляции не будет, и с анонимными неймспейсами надо быть сильно аккуратнее.

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

НЛО прилетело и опубликовало эту надпись здесь

 Ему про модули говоришь, а он всё в терминах хедеров и текстового препроцессора думает.

в статье чётко написано, "Глобальный неймспейс" "непересекающиеся имена, что вам что их написать что ли"

ill-formed, no diagnostic required.

в условиях одного TU эта проблема как раз исчезает, т.к. компилятор может диагностировать всё

то тут где вопрос компилятору?

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

НЛО прилетело и опубликовало эту надпись здесь

Куча NDR описана именно так потому, что их надёжная диагностика (в смысле decision problem) эквивалентна проблеме останова.

куча связана с тем что есть независимые TU, немного связано с формальностями в шаблонах, вот и всё

НЛО прилетело и опубликовало эту надпись здесь

 Даже NDR'ность бесконечного цикла без сайд-эффектов

это не IFNDR, а undefined behavior

НЛО прилетело и опубликовало эту надпись здесь

IF/NDR - лексически неверный код. UB - семантически неопределённый код. Программа не может быть IF/NDR .потому что ее нет. Есть какой-то непонятный артефакт (если есть).

НЛО прилетело и опубликовало эту надпись здесь

я немного потеря нить разговора но как минимум то что a * a * a + b * b * b выходит за пределы используемого типа и итерироваться уже можешь не до a < UINT_MAX а до того когда всё выражение будет a * a * a + b * b * b меньше UINT_MAX , как это гарантировать не задача компилятора и ни когда не должна ей быть

НЛО прилетело и опубликовало эту надпись здесь

Это не IFNDR, IFNDR назначается явно. Например, достижение точки выхода из функции, не возвращающей void, без return - IFNDR.

[intro.progress]  не определяет такой ситуации применительно к циклу while (for и do-while наследуют поведение while), поэтому она не определена "by omission". Это UB, в связи с проблемой найти побочные эффекты и точку выхода, что возможно только при соблюдении требований в [intro.progress].

Причём UB в ряде случаев может случиться и в компиляторе. Он попытаться развернуть ваш бесконечный цикл, считая что из него можно выудить константный результат и получится что-то... или программа (компилятор) упадет.

НЛО прилетело и опубликовало эту надпись здесь

Учтивая то, с чем программы линкуются. то это как минимум - весь код ядра, компилятора, библиотеки времени исполнения и всех библиотек. А дальше возникает проблема о которой большинство программистов на языках "высокого" уровня не задумывается.. Как быть с поздним связыванием? Как быть с совместимостью? И на чем компилировать. Даже сейчас компиляторы вроде gcc или Майкрософта могут исчерпать память на ОДНОМ файле в некоторых проектах. Глобальное , однородное, неупорядоченное пространство имеет в основном возможность существовать только в системах похожих на виртуальные машины, и то только в пределах одной "сборки". Т.к. обычно эти системы - Java, C-шарп все-таки имеют какое-то позднее связывание.

Позднее связывание подразумевает упорядочивание определений, и все те же проблемы нарушения ODR появляются на уровне "библиотека А использовала версию Х модуля Б, а библиотека Ж использовала версию Y модуля Б".

C++20 modules примерно это и реализуют.

Их долго делали как раз отчасти потому, что необходимо было обеспечить взаимодействие системы сборки и компилятора, когда компилятор сначала анализирует файлы чтобы составить список зависимостей, чтобы потом обеспечить сборку.

В стандарте вроде же нет такой штуки, как система сборки. На сколько я помню историю тикета про модули в репе cmake, то там отдельные реализации для gcc и clang ибо компиляторы отдают списки зависимостей в разных форматах.

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

p1689 как раз был создан для стандартизации формата файла зависимостей.

Если я не ошибаюсь, то модули как фича в себе были добавлены в компиляторы раньше, чем поддержка p1689, но без системы сборки их применение было не очень удобным, так как был важен порядок передачи файлов в компилятор.

Я правильно понимаю, что p1689 ещё не принят? Там вроде pending стоит у последней ревизии.

С мой колокольни история с модулями выглядит так:

Комитет: мы тут придумали модули на все случаи жизни, но нас совершенно не колышит, смогут ли компиляторы это реализовать. Системы сборки? Какие системы сборки, мы пишем стандарт и не знаем ничего о системах сборки.

Разработчики cmake: issue про поддержку модулей была открыта 5 лет назад, пора бы уже хоть какую-то реализацию сделать. Ну и заодно p1689 напишем

gcc14+, clang16+, visual studio 2022 поддерживают p1689

Тут ещё вопрос доступности. На видео поставил студию и вперёд.

А как жить в Debian? В bullseye стандартная версия 10.2 емнип. В инструкцию по сборке проекта сначала включать инструкцию по сборке компилятора под целевую ОС?

НЛО прилетело и опубликовало эту надпись здесь

параллельная (независимая) компиляция, отсутствие перекомппиляции всего, если ты изменил реализацию, гибкость - можно пожертвовать инкрементальной компиляцией и ускорить сборку

НЛО прилетело и опубликовало эту надпись здесь

Спросите у стариков сколько времени собирался проект на Delphi. И воспользуйтесь мудростью якобы турецкой поговорки

Не важно как далеко ты ушёл по неверной дороге, возвращайся назад.

А вопрос о том почему во всех сколь бы то ни было популярных языках есть show stopper, он же deal breaker, есть конспирология. А вопрос почему когда его маловато, как в случае Julia которая конспирологически не просто так, демонстративно но по итогу не вполне удачно, открещивалась от самой идеи создания "приложений", регулярно проводятся медийные кампании - тоже коспирология.

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

Они бегут не на Java, они бегут от Win32

А сейчас набирает популярность Rust...

Спросите у стариков сколько времени собирался проект на Delphi.

Довольно шустро. Но сейчас я пишу в основном на C++ (реже Phyton и старое C)....

Хотя Delphi (Visual Pascal) стоит.

А сейчас набирает популярность Rust...

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

В дельфях не просто шустро -- иногда в сотни раз шустрей, чем на сях... Плюс там достаточно надёжная типизация (и отсутствие надёжности и си), и модули, а не дурные инклуды... Собсно, главный недостаток -- что пошли по пути копирования функционала жабы/сишарпа, а не с++ (убогие генерики вместо полноценных шаблонов, например).

Как человек, периодически занимающийся реверс-инжинирингом, я считаю "полноценные шаблоны" одним из самых вредоносных функционалов C++. Когда ты в пределах одной DLL или EXE встречаешь уже пятую реализацию одного и того же класса-шаблона с разными параметрами, то можно слегка озвереть.

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

Про шаблоны - ни слова. :-(

Банальное добавление элемента в вектор ведь тоже несет некие затраты? Тем более если происходит реаллокация, а она может быть уууух какая...

+100

В других языках подобное действие совершается магией и не вызвает реаллокаций и накладных затрат.

проблема не релокациях как таковых, а в том, что может вызываться деструктор\конструктор у элементов вектора.

Либо они совершаются так же, либо их там нет.

Лично для меня еще существенным минусом является вынесение общих функций наружу, вместо использования их как функций‑членов класса. Мне, например, гораздо проще и очевиднее вызвать myVector.find_if() через точку, чем вызывать ее как внешнюю функцию с передачей итераторов внутрь.

Общие алгоритмы работают для любых контейнеров, в том числе и самописных, если их итераторы удовлетворяют явным требованиям и инвариантам STL. Это избавляет от необходимости писать весь этот код для самописных контейнеров, при этом контейнеры могут не знать о существовании стд алгоритмов впринципе.

SFINAE

Just use c++20 and requires

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

Нельзя.

Рассмотрим пример
dynamic_cast<> и RTTI (runtime type information). Это отключаемая фича в С++, но по-дефолту она включена и многими используется. Многими программистами С++ она воспринимается как бесплатная, однако при включении RTTI постоянно происходит скрытая работа в рантайме.

Скрытая она только для джавистов. Если говорить про наличие typeid и прочей мишуры в бинарнике - то это копейки на фоне всего остального, что обычно зашивается в бинарник в том же гейдеве.

Лямды

Вся портянка, написанная здесь - это буквально, в шарпах менее понятный синтаксис, подходящий в очень узких кейсах и не подходящих в других. Лямбды в плюсах позволяют писать матчеры, compile-time обходы, триллион всего, имеют контроль над лайфтаймами, то, что они захватывают, что они принимают как аргумент и что возвращают. Ну да, это приходится писать, хотя язык уже позволяет, например, опускать (), если они пустые. Проблема-то где?

IDE

Нытье про MSVC/Xcode - это просто нечто. Just use vscode, clangd + пачка плагинов = нелагучее и достаточно эффективная IDE. Дебаггер только чутка тупой, но если сильно приспичит много дебажить, то можно и CLion запустить. Clion Nova так ещё менее лагучаяя, может на неё все переедут.



НЛО прилетело и опубликовало эту надпись здесь

Важно не то, что зашивается в бинарник, а то, что засоряет кэши.
Какие кеши? RTTI не попадёт в кеш, если он не используется.
(и это я ещё GADT не брал в расчёт), и тогда можно будет обсудить, какие матчеры они позволяют писать.
Ещё бы Хаскелл не был уродским и неудобным во всём остальном)
В других языках есть просто нормальный компилтайм-язык, а не вот эти кусочки, разбавленные бочкой известно какой субстанции
В каких?
Не «имеют контроль», а «требуют от программиста контролировать». Это слегка разные вещи, я бы даже сказал, противоположные.
Где?

НЛО прилетело и опубликовало эту надпись здесь

Процессорные. typeinfo достаточно часто кладётся компилятором прямо рядом с vtbl, так что попадает и засоряет, если vtbl используется. А там и имя типа, например, есть, которое может занимать килобайты в случае какой-нибудь темплейтной хренотени.

интересное у вас понимание кешей, наверное процессор сидит и думает, ну вот втейбл же, наверное надо и имя загрузить, целиком, ну на всякий случай

 хаскеле в виде TH

В хрусте

В языках с QTT в 0-аннотированном фрагменте

какое потрясающее перечисление широкоиспользуемых языков

НЛО прилетело и опубликовало эту надпись здесь

да не нельзя, потому как там где нет возможности использовать современный стандарт C++ то и другой язык использовать там не получится так что когда мы говорим про преимущества перехода на "другой" язык то и сравнивать нужно с последним стандартом C++

НЛО прилетело и опубликовало эту надпись здесь

а каким образом эти портянки старого кода с вашим кодом на хаскеле тогда взаимодействовали и что мешало тоже самое делать с кодом написаном на новой версии компилятора, да и зачем там что то было переписывать, я вот буквально на днях апгрейдил тулчейны для кода 30 летней давности, все что потребовалось это добавить пару опций компиляции для игнорирований новых предупреждений и добавить const в паре мест для char*. Я не пытаюсь докопаться, просто для меня это максимально странно выглядит.

В другой компании нельзя было использовать последние компиляторы из-за несовместимости ABI с поставщиком закрытой библиотеки для парсинга сообщений от биржи, тогда как на хаскеле парсер пишется за пару вечеров.

не будем про то что поставлять проприетарные либы с C++ API это моветон, но хотелось бы уточнить, правильно ли я понимаю, вместо того чтобы написать тот же парсер на каком ни будь ragel или re2c и работать с ним в той же самой "экосистеме" и не заводить новых языков было решено переписать его на haskell? Тут явно нужно знать больше контекста потому что в отрыве это какой то странный мув безумного хаскелиста...

НЛО прилетело и опубликовало эту надпись здесь

втейбл  и RTTI не находятся в объекте, там только указатель на первый. Да, вот этот указатель и есть вся нагрузка... И это не индивидуализированная информация, мы не в LUA где виртуальные таблицы на ходу можно редактировать.

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

Можно. Просто LUA задумывался так. Не даром на нем сталиGUI для игр делать или внутреннюю логику (как в X2). Например гибкий интерфейс World of Warcraft. Blizzard аж пришлось блокировать часть функционала, т.к. люди стали писать автоматическое целеуказание для ПВП и ботов прямо на движке игры.

И так как там успехи с аналогичными матчерами, чтобы не делать гроздья вложенных std::visit (в которых fallthrough всё равно невыразим)?

[](auto&&){}

Что «где»? Контролировать где? Там, где язык не даёт никаких гарантий, будет ли жить то, что вы захватили по ссылке, всё время жизни лямбды.

Ты понимаешь, что любая гарантия - это оверхед? Почему кто-то тебе что-то должен гарантировать? Хочешь гарантировать - гарантируй: юзай шареды, интрузивы, что угодно. Не хочешь - не юзай. Лямбда - это языковой механизм.

НЛО прилетело и опубликовало эту надпись здесь

Можете развернуть мысль?

предполагаю это относилось к "которых fallthrough всё равно невыразим)", что как раз таки и является обработкой fallthrough

НЛО прилетело и опубликовало эту надпись здесь

Только не всегда это рантайм-оверхед.

Всегда. Тот факт, что вы думаете, что его нет - не означает, что его нет.
И да, отсутствие гарантий — тоже оверхед, просто на программиста.

Бла-бла-бла. С таким же успехом можно юзать гараж коллектор.

А можно мне как-то семантика языка будет это гарантировать во время компиляции, а не рантайм-механизмы во время выполнения? Я не хочу платить за шареды, интрузивы и другие красивые слова.

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

НЛО прилетело и опубликовало эту надпись здесь

Если функция принимает ссылку на struct Foo}туда может прийти часть области памяти класса Boo, унаследованного от Foo, или класса, содержащего Foo, или настоящий Foo, не так ли. Но без RTTI - это задача программиста проследить чтобы функция не пыталась выйти за границы и сделать upcast неправильно. Однако RTTI содержится не во всех классах.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

ламда вставленная в шаблон далеко не всегда оверхэд, часто наоборот. Практика показала что компиляторы вмонтируют ее в код алгоритма. Что может не происходить с функциями, т.к. явно берётся адрес функции. Я уже не говорю о bind, или std::function, там вообще виртуальная диспетчеризация.

Один коллега наоборот жаловался что он не может отлаживать "эти смайлики", отладчик в них "не заходит". Исследование показало, что мелкософт по умолчанию включает function inlining в отладке, его надо было выключить.

Ещё бы Хаскелл не был уродским и неудобным во всём остальном)

По-моему один из самых красивых языков. Раскройте в чём уродство, пожалуйста

Покажите матчер, который делает что-то, эквивалентное

А та часть матчера, которая по значениям, она какая-то особенная, или просто сахар для if-else'ов?

НЛО прилетело и опубликовало эту надпись здесь

Да миллион способов написать тоже самое на C++ вот первые пришедшие в голову, да оно чуть более многословное но зато гораздо эффективнее, 4 вариант вообще инлайнит строчку вместо всех вызовов и сравним это с тем что нам нагенерит ghc https://gcc.godbolt.org/z/Md4xEqcdh

Hidden text
struct B1 {};
struct B2 {};
using Bar = std::variant<B1, B2>;
struct C1 {
    int v;
};
struct C2 {
    Bar bar;
};
using Foo = std::variant<C1, C2>;

namespace foo1 {
    template<class... T>
    std::string_view to_string(const std::variant<T...>& variant);

    std::string_view to_string(const B1&) {
        return "cb1";
    }

    std::string_view to_string(const B2&) {
        return "cb2";
    }

    std::string_view to_string(const C1& c1) {
        if (c1.v == 0) {
            return "c1 zero";
        }
        if (c1.v > 0) {
            return "c1 pos";
        }
        return "c1 neg";
    }

    std::string_view to_string(const C2& c2) {
        return to_string(c2.bar);
    }

    template<class... T>
    std::string_view to_string(const std::variant<T...>& variant) {
        return std::visit([](auto&& arg) { return to_string(arg); }, variant);
    }

}  // namespace foo1

namespace foo2 {
    template<class... Args>
    std::string_view to_string(const std::variant<Args...>& variant) {
        auto constexpr visitor = []<typename T>(T&& arg) -> std::string_view {
            if constexpr (std::is_same_v<T, C1>) {
                if (std::get<C1>(arg).v == 0) {
                    return "c1 zero";
                }
                if (std::get<C1>(arg).v > 0) {
                    return "c1 pos";
                }
                return "c1 neg";
            }
            if constexpr (std::is_same_v<T, B1>) {
                return "cb1";
            }
            if constexpr (std::is_same_v<T, B1>) {
                return "cb2";
            }
            if constexpr (std::is_same_v<T, C2>) {
                return to_string(std::get<C2>(arg));
            }
            return "";
        };
        return std::visit<std::string_view>(visitor, variant);
    }

}  // namespace foo2
namespace foo3 {
    auto to_string(const Foo& foo) {
        switch (foo.index()) {
        case 0:
            if (std::get<0>(foo).v == 0) {
                return "c1 zero";
            }
            if (std::get<0>(foo).v > 0) {
                return "c1 pos";
            }
            return "c1 neg";
        case 1:
            switch (std::get<1>(foo).bar.index()) {
            case 0:
                return "cb1";
            case 1:
                return "cb2";
            }
        }
        return "";
    }
}  // namespace foo3
namespace foo4 {
    template<class... Ts> struct match : Ts... { using Ts::operator()...; };
    template<class... Args>
    std::string_view to_string(const std::variant<Args...>& foo) {
        match data{
            [](const C1& c1) {
                 if (c1.v == 0) {
                     return "c1 zero";
                 }
                 if (c1.v > 0) {
                     return "c1 pos";
                 }
                 return "c1 neg";
             },
             [](const C2& c2) { return to_string(c2.bar); },
             [](const B1&) { return "cb1"; },
             [](const B2&) { return "cb2"; }
        };
        return std::visit<std::string_view>(data, foo);
    }

}  // namespace foo4

int main() {
    Foo f = C1{1};
    std::cout << foo1::to_string(f) << std::endl;
    std::cout << foo2::to_string(f) << std::endl;
    std::cout << foo3::to_string(f) << std::endl;
    std::cout << foo4::to_string(f) << std::endl;
}

Да миллион способов написать тоже самое на C++ вот первые пришедшие в голову, да оно чуть более многословное но зато гораздо эффективнее

"чуть более многословное", а под спойлером 124 строчки кода вместо 10 )))

Там 4 разных варианта, и у последнего варианта будет 14 строк если ужать переносы }

Примеры неэквивалентны: если есть variant<A, variant<A, B>>, то 4 вариант, например, все А обработает одинаково, независимо от уровня вложенности.

Согласен можно конкретизировать и немного убрать лишнее парой строчек

namespace foo5 {
    template<class... Ts> struct match : Ts... { using Ts::operator()...; };
    template<class... Types, class... Fn>
    constexpr auto mather(const std::variant<Types...>& foo, Fn... fn) {
        return std::visit(match{std::forward<Fn>(fn)...}, foo);
    }
    template<class... Args>
    constexpr std::string_view to_string(const std::variant<Args...>& foo) {
        return mather(foo, 
            [](const C1& c1) {
                 if (c1.v == 0) {
                     return "c1 zero";
                 }
                 if (c1.v > 0) {
                     return "c1 pos";
                 }
                 return "c1 neg";
            },
            [](const C2& c2) {
                 return mather(c2.bar, 
                    [](const B1&) { return "cb1"; },
                    [](const B2&) { return "cb2"; }
                 );
            }
        );
    }
}

Ну можно тогда до конца пойти и убрать лямбду в лямбде:

template<typename... Ts>
struct overload : Ts... { using Ts::operator()...; };

template<typename T, typename... Fs>
class lvl
{
public:
    lvl(Fs... fs) : ov{fs...} {}

    template<typename U>
        requires (std::is_same_v<std::decay_t<T>, std::decay_t<U>>)
    decltype(auto) operator()(U u) {
        return std::visit(ov, u);
    }

private:
    overload<Fs...> ov;
};

template<typename T, typename... Fs>
auto l(Fs... fs) { return lvl<T, Fs...>(fs...); }

struct A {};
struct B {};
struct C {};
using v1 = std::variant<A, B>;
using v2 = std::variant<A, int, v1>;

void test(v2 v)
{
    auto matcher = overload{ [](int i) { /*...*/ },
                             [](A) { /*...*/ },
                             l<v1>( [](A) { /*...*/ },
                                    [](B) { /*...*/ } ) };

    std::visit(matcher, v);
}

да, можно но я пытался балансировать между шаблонным безумием и близости к стилю хаскеля, сохраняя хоть какое то соотношение полезного кода к обвязке) можно было бы ещё и макросов добавить но боюсь тогда "контр пример" выглядел бы совсем смешно и нелепо)

НЛО прилетело и опубликовало эту надпись здесь

 (и лишнюю функцию он вырезал, в отличие от плюсов).

кто это сказал, что она лишняя? Добавите флаг, чтобы он мержил одинаковые функции - он будет мержить, иначе это некорректно например из-за адресов функций.

Если у вас появляются функции с одинаковым содержанием, то вы что-то делали не так

НЛО прилетело и опубликовало эту надпись здесь

Не подскажете название? В таких деталях я не спец.

этим занимается линкер, ему флаг и передавайте, со стороны компилятора -ffunction-sections

Вполне нормальная ситуация при 

неправильном коде

НЛО прилетело и опубликовало эту надпись здесь

Я вам даже пример привёл.

так писать не надо, в этом и суть

В моём же примере из предыдущего комментария не помогло.

потому что смотрите на годболте (где показывается аутпут компилятора, а не всего процесса компиляции) и не прокинули флаг линкеру

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Помогает не генерировать одинаковый код для разных типов или я не понял в чем была претензия тогда.

НЛО прилетело и опубликовало эту надпись здесь

так у тебя 2 публичные функции с разными сигнатурами которые должны быть доступны по своим именам или ты предлагаешь чтоб весь код std::accumulate не инлайнился а зачем то создался ещё один метод который бы вызывался из foo и bar чтоб даунгрейднуть перфоманс, все ещё не понимаю притензии

НЛО прилетело и опубликовало эту надпись здесь

Плюсы direct и patterns компилируют в один и тот же код, но и ghc компилирует direct и patterns не то что в один и тот же код, а вообще вырезает direct и проксирует вызов в patterns:

а толку то когда реальный выхлоп всё ещё в 10раз больше

а все эти "кучу интересных вещей, вроде worker/wrapper " резко обламываются когда сталкиваются с реальным миром и реальным железом и уж тем более когда речь заходит о реальной оптимизации под железо. Очень было бы интересно посмотреть на пример где это "на практике" быстрее.

Оно гораздо более многословно, особенно когда у вас будет больше одного аргумента, или в некоторых guard'ах будут какие-то действия, и так далее.

Нет не будет просто не нужно писать на C++ как на хаскеле, стоит не забывать что эти примеры сделаны специально максимально приближенными к хаскель стилю что в реальности не имеет ни какого реального смысла, это просто пример гибкости языка и в проде я бы ни когда так писать не стал.

Более того, в C++-версии очень легко случайно сделать UB, которое компилятор вам нифига не поймает (привет Kelbon'у с его «ловит всё»), даже если его можно вырезать: https://gcc.godbolt.org/z/TzohY44bW . ghc пофиг на лишний вызов, он генерит код как раньше, а вот в C++ вся эта красота разваливается.

"Доктор, когда я делаю вот так, у меня тут болит"

НЛО прилетело и опубликовало эту надпись здесь

Нормально там всё оказывается, чай, продакшен-левел компилятор, а не идрис какой-нибудь :]

питон тоже уже лет 30 как продакшен реди только быстрым его это не делает

Ну это очень удобно, конечно

конечно удобно ведь c++ не ограничен какой то одной парадигмой и при столкновении с реальным миром у которого есть и глобальные состояния и модифицирующие действия не нужно переходить на другой язык чтоб "не нарушать, "красивую" идею pure functional

Так что будь хаскель таким быстрым и удобным как вы его описываете геймдев был бы не на c++

и если честно я половину объяснения про wrapperы просто скипнул, по мне это все абсолютно бессмысленная и бесполезная дичь, в реальном мире у нас есть конкретнаая память, конкретные буфферы и данные в байтих. я даже примерно не представляю что в ghc это такое "боксингПослеG ∘ g' ∘ анбоксингДоG ∘" и в какой ассемблер это превращается и уж тем более как при всей этой мат.абстракции он может использовать векторные инструкции, с c++ для меня все плюс минус пркдсказуему.

НЛО прилетело и опубликовало эту надпись здесь

ну там, SSA, раскраски графов всякие, всё такое

да там норм, там это относится к реальности и операциям в реальном железе, а как все эти композиции функций, манады и "бесконечные ленивые списки" к реальности относятся я не понимаю.

А в хаскеле нужно, что ли?

сразу извиняюсь за глупыый вопрос, а в хаскеле можно написать io монаду на чистом хаскеле?

Угу, я тут в соседнем треде пример приводил

странный кейс, я бы посмотрел, но я не про предсказуемость циферок, а про предсказуемость итоговой стейт машины в которую компилится мой код. когда я пишу что A вызывает в цикле B то я это и вижу в ассемблере, в заинлайненом виде или же с разворачиванием циклов не суть важно

Легаси-причины — имеющиеся

геймдев убъется за лишние пару процентов перфоманса так что не думаю что дело только в "легаси", так же как гугл, майки и все прочие мега корпорации тратящие огромные деньги на то чтоб ещё больше оптимизировать C++ каждый год чтоб экономить на своих серверах

НЛО прилетело и опубликовало эту надпись здесь

А в C++ можно написать аллокатор памяти на чистом C++, без ассемблера и дёрганья железа?

а кто запрещает то? я то чтоб большой писатель кастомных аллокаторов, но tcmalloc как то же написан на C++, как то ядро linux на C написано, много там ассемблера то?

гугл придумал go

вот только почему то свой поисковой движёк на него не перевел

НЛО прилетело и опубликовало эту надпись здесь

что значит не полезет в ядро? ОС занимается меджментом памяти, на микро контроллерах размечается память на старте, но вызов сискола это ещё не ассемблер да и причем тут сравнение с ассемблером, C и C++ можно напрямую делать вставку ассемблерного кода и в этом нет ни каких идеологических противоречий, не помню что б в хс можно было иметь глобальные объекты и уж тем более вставки кода на C делать, так что эта попытка притянуть то что в C есть ассемблер не в тему, они специально написаны так чтоб можно было использовать асм напрямую и от него не отгораживаются в отличие от всяких функциональных языков которые пропагандируют "чистые функции"

НЛО прилетело и опубликовало эту надпись здесь

Правда? Научите делать сисколлы без ассемблера плиз.

не благодари: https://man7.org/linux/man-pages/man2/syscalls.2.html

семантику чего?

Можно, конечно.

Вот чего не знал того не знал, это забавно.

Не вижу ничего плохого в огораживании от потенциально опасных вещей при возможности их всё равно делать.

я вижу в этом небольшое лицемерие, как в расте с его unsafe и криками на каждом шагу "у нас самый безопасный язык"

Там пропагандируют не чистые функции, а контроль за эффектами в типах.

я возможно дурак, но не вижу разницы

НЛО прилетело и опубликовало эту надпись здесь

Что, по-вашему, происходит, когда вы делаете read(2)

вызывается другой сишный код) это не апи в том же понимании что и в языках типа хаскель, это уроверь ядра ОС, не помню что б хаскель на голом железе мог запускать в отличае от C, что б ввязываться вообще в эту дискуссию на тему "а чёй то у вас под капотом ассемблер есть" он и у хаскеля есть, только страшный и не красивый)

Ну деюро нет, дефакто есть, так что какая разница?) и опять же за них ни кто в C/C++ мире не осудит, в отличае от функциональщиков.

В чём лицемерие? 

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

А ещё в том что "мы против глобальных объектов, мутабельности и сделаем все чтоб это было делать больно и сложно", но оказывается что без этого язык совершенно бесполезен и все же окошечко в реальный мир пробивать приходится и не суть важно как, будь то монада IO или unsafe. И вот в этот момент я всегда задаюсь вопросом, а зачем мне трудности самому себе создавать, когда можно просто использовать правильный тулинг и style гайды, в место того чтоб маяться дурью в виде борьбы с borrow чекером. Замени все сырые указатели на shared/weak поинтеры и 90% проблем будут так же просто решены. Если хочется ещё ближе к расту можно заменить на uniq и вообще отличий практически не будет.

НЛО прилетело и опубликовало эту надпись здесь

Любопытно. Но если вы сами прорубите окно в реальный мир, то окажется что ваши зависимости не следуют вашим style гайдам. Более того, они и тулингом могут быть не покрыты, и тестами.
А вот компилятор может обнаружить ошибку сразу, без доп инструментов, и его невозможно не запустить.

Кстати, тулинг ловит не все ошибки, об этом чуть выше писали.
А С++ ругают за тысячи UB, из которых многие можно было бы сделать хотя бы unspecified behavior или platform-dependent.

А что мешает зависимостям раст нагадить утечками в unsafe? в C++ у меня хотя бы есть valgrind, статические анализаторы кода, адрессанитайзеры и ещё миллиард всего что поможет мне найти эту проблему и решить.

1) Тем что стандартная библиотека Rust почти на 100% формально верифицирована именно чтобы устранить баги с unsafe.
https://github.com/rust-lang/miri-test-libstd
2) Тем что в Rust принято формально верифицировать библиотеки, работающие с unsafe. Для этого есть соответствующие инструменты (https://github.com/rust-lang/miri/, https://github.com/formal-land/coq-of-rust и т.д.), и ими реально пользуются.
3) Наконец есть valgrind, адрессанитайзеры и прочие инструменты, которые работают как с С++, так и с Rust.
Статические анализаторы тоже есть, хотя не совсем понятно зачем они нужны после всего вышеперечисленного.

  1. miri это никакая не "формальная верификация" это санитайзер

  2. coq уже больше похоже на правду, но реально им никто не пользуется

  3. наличие санитайзеров для раст подтверждает что нифига формально не верифицировано и по факту для отлова уб используются утилиты заимствованные из С++. Только интеграция с раст там хуже.

  1. Ок, по п.1 мне нужно было скинуть ссылку из п.2. И тем не менее:
    libcore https://github.com/formal-land/coq-of-rust/tree/main/CoqOfRust/core
    liballoc https://github.com/formal-land/coq-of-rust/tree/main/CoqOfRust/alloc

  2. см. п1

  3. Каким образом Miri заимствован из C++? Кстати модель ссылок StackedBorrows в нем формально верифицирована. И некоторые другие его части тоже.

Ок, по п.1 мне нужно было скинуть ссылку из п.2.

Эти два пункта вообще не связаны, кок и мири это два разных подхода.

И тем не менее:

и тем не менее в тех директориях гита просто кодоген который гоняет код из одной репрезентации в другую. Каким образом он что то верифицирует?

Каким образом Miri заимствован из C++

зачем вы пытаетесь передергивать? И ежу очевидно что мой комментарий был про все остальные сантайзеры из вашего пункта (3). По miri это был пункт (1). Но рад что вы согласились что мири это санитайзер а не формальная верификация.

Кстати модель ссылок StackedBorrows в нем формально верифицирована.

Речь о проверке кода, при чём тут верификация какой-то модели? Вы сели в лужу со своим предыдущим тезисом и теперь пытаетесь приплести слово верификация хоть куда-то.

по факту для отлова уб используются утилиты заимствованные из С++

Нет, это вы сели в лужу, т.к. по факту везде используется miri, не имеющий отношения к С++. Но если очень хочется, то можно использовать valgrind и т.д.

coq уже больше похоже на правду, но реально им никто не пользуется

Я отвечал на это, и привел пример что используется.

по факту везде используется miri, не имеющий отношения к С++.

Наконец есть valgrind, адрессанитайзеры и прочие инструменты, которые работают как с С++, так и с Rust.

Вы там определитесь какие инструменты используются а какие нет, и тогда пишите. Подсказка: используются разные т.к. мири проверят только малую часть проблем, а именно правила бч, и то теряет информацию когда происходит много кастов в сырые поинтеры.

Я отвечал на это, и привел пример что используется.

И что же там используется? Есть какой-то транслятор, а сами пруфы не наблюдаются. И это только стандартная либа, а еще для сотен крейтов никто даже этот трансформатор вообще не запускал. И вы не поверите, но для си тоже есть методы формальной верфикацией.

Нет, пример был про Miri, в нем формально проверили правила borrow checker, заодно проверив и компилятор в части borrow checker. Вы же утверждали, что coq не используется совсем.

Кроме того проверять нужно только крейты, который активно используют unsafe, но при этом нет unsafe во внешнем API. В моей предметной области (микроконтроллеры) таких ровно 2: embassy-sync и heapless.

Кроме того проверять нужно только крейты, который активно используют unsafe, но при этом нет unsafe во внешнем API.

таких 20 процентов согласно раст статистике

Тем что стандартная библиотека Rust почти на 100% формально верифицирована именно чтобы устранить баги с unsafe. <Ссылка miri-test-libstd>

Вот тут вы рассказли про верефикацию стд библиотеки и привели ссылку на мири. Мири не делает формальную верификацию стд библиотеки потому что мири это санитайзер. Вы ошиблись. Я указал вам на эту ошибку.

Нет, пример был про Miri, в нем формально проверили правила borrow checker

Фраза "формально проверили правила borrow checker" сама по себе не имеет смысла. Что именно проверили? Что правила не противоречивы между собой? Выражайтесь в следущий раз яснее. Возможно для этого полезно ознакомится с темой более глубоко прежде чем делать громкие заявления.

Вы же утверждали, что coq не используется совсем.

Где я это утверждал? Что значит совсем? Вообще в мире?

таких 20 процентов согласно раст статистике

Статистику в студию!

Вот тут вы рассказли про верефикацию стд библиотеки и привели ссылку на мири. Мири не делает формальную верификацию стд библиотеки потому что мири это санитайзер. Вы ошиблись. Я указал вам на эту ошибку.

Согласен, тут я ошибся.

Где я это утверждал? Что значит совсем? Вообще в мире?

Вы утверждали, что coq никто не пользуется в Rust. Не передергивайте, вот ваша цитата:

coq уже больше похоже на правду, но реально им никто не пользуется

Далее:

Фраза "формально проверили правила borrow checker" сама по себе не имеет смысла. Что именно проверили? Что правила не противоречивы между собой?
Выражайтесь в следущий раз яснее. Возможно для этого полезно ознакомится с темой более глубоко прежде чем делать громкие заявления.

Предлагаю вам ознакомиться с первоисточником:

In this work, we propose Stacked Borrows, an operational semantics for memory accesses in Rust. Stacked Borrows defines an aliasing discipline and declares programs violating it to have undefined behavior, meaning the compiler does not have to consider such programs when performing optimizations. We give formal proofs (mechanized in Coq) showing that this rules out enough programs to enable optimizations that reorder memory accesses around unknown code and function calls, based solely on intraprocedural reasoning. We
also implemented this operational model in an interpreter for Rust and ran large parts of the Rust standard library test suite in the interpreter to validate that the model permits enough real-world unsafe Rust code

https://plv.mpi-sws.org/rustbelt/stacked-borrows/paper.pdf

Статистику в студию!

тут https://foundation.rust-lang.org/

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

Так а сколько кода реально верифицировано? Думаю мало. В коммерческой разработке я думаю это не выгодно. А так да, можно вспомнить https://frama-c.com/ , тоже верификация. Тут утилита семантику си понимает. В случае с растом была история c проверкой std::, но афаик было много ручной работы всё равно. И с тех пор уже сколько изменений внесли в код, а статью выпустили один раз, грант отработали и всё. Что-то автоматическое есть по вашей ссылке, но там собственно самих пруфов не видно. Так что пока это всё реклама.

Предлагаю вам ознакомиться с первоисточником

С таким успехом я могу первоисточник сам прочесть. Зачем на хабр заходить...

тут https://foundation.rust-lang.org/

Ага, и там же написано:

Most of these Unsafe Rust uses are calls into existing third-party non-Rust language code or libraries, such as C or C++.

Так что все зависит от ваших зависимостей. Если добавлять библиотеки-обертки из C, C++ и других языков, то там конечно будет unsafe. Ну и конечно API ОС:

In fact, the crate with the most uses of the unsafe keyword is the Windows crate [7], which allows Rust developers to call into various Windows APIs.

Впрочем то же самое будет в любом языке, использующем код другого языка, только не будет помечено unsafe (хотя в C-Sharp есть свой unsafe).
Но соотношение 20/80% намекает, что для часто используемых областей написаны библиотеки на чистом Rust без единой строчки unsafe.

Так а сколько кода реально верифицировано? Думаю мало.

Я к тому и веду, что вы тоже были не правы, что coq совсем не используется. А сейчас выяснилось, что вы читали первоисточник, и все-же категорично утверждали обратное.

Так замеры делало rust foundation. Всё что написано в этой статье нельзя считать объективной информацией. Понятно что задача раст евангилистов убедить нас в том что это нестрашно, рассказать что это виновата ОС и кто угодно кроме них. А чтобы оценить сколько реально ансейф процентов в итоговом продукте, надо сравнивать сколько функционала за теми С/С++ обертками. При том как то умнее чем просто по количеству строк, потому что раст очень вербозный.

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

Утверждал что не используют для верифиакции библиотек. То что модель мири как-то покрутили в коке на предмет совместимости с какой-то моделью оптимизаций - не знал.

Так замеры делало rust foundation. Всё что написано в этой статье нельзя считать объективной информацией. Понятно что задача раст евангилистов убедить нас в том что это нестрашно, рассказать что это виновата ОС и кто угодно кроме них. А чтобы оценить сколько реально ансейф процентов в итоговом продукте, надо сравнивать сколько функционала за теми С/С++ обертками. При том как то умнее чем просто по количеству строк, потому что раст очень вербозный.

Они просто подсчитали крейты, в которых есть хотя бы 1 строчка unsafe. Это вполне объективная информация для данной простой модели подсчета.

Of those 127,000 crates, 24,362 make use of the unsafe keyword, which is 19.11% of all crates. And 34.35% make a direct function call into another crate that uses the unsafe keyword. [6] Nearly 20% of all crates have at least one instance of the unsafe keyword, a non-trivial number.

Другую статистику никто не посчитал. Но не потому что это заговор каких-то там евангелистов, а потому что это сложнее, и надо договориться по методике которая всех устроит.

Но если подсчитать, то может внезапно выясниться, что среди тех 19.11% крейтов многие написаны во времена выхода Rust 1.0 и не поддерживаются (аналогичные проблемы есть и в других пакетных менеджерах, например npm).

Кроме того надо еще исключить пакеты с 10 строчками кода, выложенные ну просто потому что хотелось попробовать выложить (опять те же претензии к npm).

Вобщем все сложно, но ведь это вы сослались на эту статистику, и постом ниже уже считаете её необъективной xD.

Понятно что задача раст евангилистов убедить нас в том что это нестрашно, рассказать что это виновата ОС и кто угодно кроме них.

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

То же относится к любым языкам, которые используют библиотеки других языков.
На Python вообще половина PyPi это обертки над С, но никто не жалуется. При этом код по сути unsafe, но ключевого слова такого нет, и за счет этого выглядит приятнее)

Так что вы предлагаете то? Или приведите пример другого языка, где FFI вделан лучше и безопасней.

Утверждал что не используют для верифиакции библиотек. То что модель мири как-то покрутили в коке на предмет совместимости с какой-то моделью оптимизаций - не знал.

Ок, принято.

Как раз то что ансейф есть в 1/5 крейтов это ок. Я вам это и сказал в первом сообщении. А все остальные цитаты и выводы из поста что вы привели, - это уже потенциально реклама.

Но если подсчитать, то может внезапно выясниться, что среди тех 19.11% крейтов многие написаны во времена выхода Rust 1.0 и не поддерживаются (аналогичные проблемы есть и в других пакетных менеджерах, например npm).

то же самое может внезапно оказаться для оставшихся 80%

Кроме того надо еще исключить пакеты с 10 строчками кода, выложенные ну просто потому что хотелось попробовать выложить (опять те же претензии к npm).

их же надо исключить из 80% пакетов без ансейф. И я уверен что те кто хотели просто "попробовать выложить" или выложить свое домашнее задание из универа выкладывали как раз крейты без ансейф. В итоге доля реальных библиотек с ансейф увеличивается.

Не возможно и не нужно переписывать все библиотеки мира на Rust.

Скажите это растоманам которые бегают по гитхабу и создают ишью вида "consider rewriting in rust". Недавно один уникум даже в Qt багтрекере такое создал. Но наверное на созданиях тикетов деятельность по переписыванию на раст обычно и заканчивается =)

На Python вообще половина PyPi это обертки над С, но никто не жалуется.

Питон не позиционирует себя как замену Си. Питон наоборот позиционирует себя как язык клей с реплом и прочим. И используется например как конфигуратор C++ ML библиотек.

Напомню ветка началась с обсуждения зависимостей. Вы жаловаолись что зависимости на си или си++ это плохо, они могут быть не протестированы санитайзерами, не следовать современным практикам и т п... А теперь оказывается "это обертки над С, но никто не жалуется" :-D

Как раз то что ансейф есть в 1/5 крейтов это ок. Я вам это и сказал в первом сообщении. А все остальные цитаты и выводы из поста что вы привели, - это уже потенциально реклама.

Значит я вас неправильно понял. Думал вы в негативном смысле написали.

то же самое может внезапно оказаться для оставшихся 80%

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

Скажите это растоманам которые бегают по гитхабу и создают ишью вида "consider rewriting in rust". Недавно один уникум даже в Qt багтрекере такое создал. Но наверное на созданиях тикетов деятельность по переписыванию на раст обычно и заканчивается =)

Я на Rust пишу с 2018 примерно, но по гитхабу так не бегаю) И я ни разу не видел чтобы переписали какой-то проект целиком на Rust (не исключаю что такое существует).
Но видел много новых библиотек, аналогичных по функционалу уже существующим на С и С++, но с другим API. Например eigen в С++ и nalgebra в Rust. Хотя казалось бы математика везде одинакова.

Напомню ветка началась с обсуждения зависимостей. Вы жаловаолись что зависимости на си или си++ это плохо, они могут быть не протестированы санитайзерами, не следовать современным практикам и т п... А теперь оказывается "это обертки над С, но никто не жалуется" :-D

Я сейчас отлистал вверх и не нашел начало ветки от Arenos, похоже он удалил сообщение (пора уже делать скриншоты..).
Но он заявлял что санитайзеры и современные практики для него лучше подходят, а компилятор Rust слишком сильно ограничивает. На это я ему и ответил, что

могут быть не протестированы санитайзерами, не следовать современным практикам и т п..

Так что я от своих слов не отказываюсь, а вы их вырвали из контекста.
Я считаю что больше гарантий от компилятора это лучше. Но Haskel пока не освоил.

Например eigen в С++ и nalgebra в Rust

До const-generics сделать что-то отдаленно похожее на eigen в расте было нельзя совсем. Сейчас const-generic тоже могут мало, для поднятия на уровень типов приходится городить такие приколы
https://docs.rs/nalgebra/0.32.1/nalgebra/base/dimension/trait.ToTypenum.html
https://docs.rs/nalgebra/0.32.1/nalgebra/base/dimension/trait.ToConst.html
с конвертацией через S-List. Кстати очень приятно потом лицезреть эти типы в километровых ошибках компиляции.
Это даже по сравнению с С++ нулевых годов смешно.

А ключевая фишка eigen в составлении пайплайнов вычисления, а потом его обработке. Эту тему я уже затрагивал тут в комментах на примере ренжей.
https://devdocs.io/eigen3/topicinsideeigenexample
В расте такого нету и сделать невозможно. Там сложение создаёт новую матрицу, а для всех симд операций отдельно захардкодены явные методы (если вообще захардкодены). Похожая идея есть и в numpy, больше в pytorch, но в питоне это всё в рантайме. С++ даёт это выразить в компайл тайм.
В nalgebra даже transpose() копирует матрицу, а transpose().transpose() делает две копии. В то время как в нормальном фреймворке эти операции не делают ничего вообще.

Вот это уже предметное обсуждение.

До const-generics сделать что-то отдаленно похожее на eigen в расте было нельзя совсем. Сейчас const-generic тоже могут мало, для поднятия на уровень типов приходится городить такие приколы

Да, const-generics пока все не очень. Надеюсь допилят.

Там сложение создаёт новую матрицу, а для всех симд операций отдельно захардкодены явные методы (если вообще захардкодены).

В eigen автоматически выбирается вариант симд, а в nalgebra нужно явно передать с использованием внешних ящиков. Не могу сказать что способ eigen всегда лучше (хотя он всегда проще), зависит от алгоритма. В некоторых случаях нужно подбирать размер симд операции (например AVX 4,8 или 16 слов) чтобы добиться максимальной производительности.
https://www.rustsim.org/blog/2020/03/23/simd-aosoa-in-nalgebra/

Про новую матрицу не понял, поясните.

В nalgebra даже transpose() копирует матрицу, а
transpose().transpose() делает две копии. В то время как в нормальном фреймворке эти операции не делают ничего вообще.

Ну это проблема в библиотеке, хз почему не реализовали.

В любом случае, nalgebra это был просто пример того, что библиотеки обычно не переписывают с С и С++ на Rust, а создают новые.

Я же объяснил, потому что eigen не выразим на расте.

Пока не выразим. Но напомните мне, через сколько лет в С++ добавили шаблоны?

И вообще это неконструктивный подход. Я тоже могу сказать, что embassy не выразим в С++. Просто потому что системы типов разные.

В чем неконструктивность если я просто констатирую факты?

А так да, будем ждать ¯_(ツ)_/¯

Я вам развернуто написал что на мой взгляд в eigen хорошо сделано, а что плохо. И чего не хватает в nalgebra и Rust.

Вы же просто заявляете "eigen не выразим на расте", и отказываетесь от нормального обсуждения. Вот это неконструктивно.

По этому возвращаю вам обратно:

Я тоже могу сказать, что embassy не выразим в С++.

Мне лень участвовать в демагогии что конструктивно а что нет.

Фичей eigen в nalgebra нету потому что их невозможно реализовать на расте.

А я вам написал, что эти фичи eigen делают невозможным выбор оптимального варианта SIMD. И это в С++, где производительность - объект поклонения каждого программиста.

А вот в Rust выбрать можно, ценой некоторого увеличения кода. При этом нельзя (пока) сделать автоматический выбор, как в eigen.

Но вы упорно отказываетесь обсуждать суть проблемы. Кто же из нас демагог?

Я не вижу как одна фича противоречит другой.

В раст я не понял как этим пользоваться. Из статьи и кода бенчмарка непонятно. Как будет индексироваться Vector3<f32x4>, индексами от 0 до 3 или от 0 до 12?

Апд исправил форматирвание

нет, я ни чего не удалял, если только кто то этого не сделал за меня

и да лучше, компиль раста слишком много требует от разработчика чтоб быть хотя бы немного полезнее C++. И все эти проблемы которые он якобы решает через чур преувеличины и раздуты сообществом растоманов.

Но вы так и не ответили на вопрос: как вы в С++ контролируете что зависимости пользуются стайл-гайдами, тулингом и т.д?

И все эти проблемы которые он якобы решает через чур преувеличины и раздуты сообществом растоманов.

Проблемы кем только ни раздуваются: Microsoft, Android, АНБ, Linux и даже Unreal Engine. И они рекомендуют переходить на более безопасные языки в целом, а не только на Rust .

1) не брать либы в которых этого нет, 2) ни как, а зачем? Есть свои unit тесты, интеграционное тестирование, санитайзеры, статический анализаторы, нормальные отладчики, профайлеры и огромное комьюнити. За десяток лет я всего пару раз находил баги в 3rd-party и правил их и то только потому что брал самые последние версии ещё не обкатанные комьюнити. И ни каких проблем с этим не увидел. Я так понимаю ошибок в 3rd-party на других языках ни когда не бывает? или к чему это?

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

И в зависимостях зависимостей проверяете?) Кроме того наличие тулинга не говорит о степени покрытия.

А баги вышеупомянутые крупные компании находят регулярно. Значит либо у вас уникальный набор зависимостей без багов, либо вы эти баги не замечаете.

Я так понимаю ошибок в 3rd-party на других языках ни когда не бывает?

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

Но пока что все эти же компании спонсируют cppcon и активно участвуют в собраниях комитета по стандартизации и развитию c++ и пропихивают свои пропозалы, а некоторые ещё и компиляторы зачем то свои пишут..

А так же спонсируют другие языки, конференции и т.д. Так что это не аргумент.

Очевидно что в других языках часть багов не возможна

это какие и в каких что их прям "не может быть"? утечка памяти и ресурсов в целом в языка с GC вроде как не уникальное явление, так же как и выход за границы, обращение к неинициализированным данным, дедлоки и всё остальное.

к обычному падению с ошибкой и стектрейсом.

а в C++ какое то необычное падение и стектрейсы? или оно в случае ошибки берет и сносит ОС? если мы конечно сравниваем языки в одинаковых задачах

не аргумент.

конечно аргумент ведь зачем они тратят усилия на всё это если cчитают C++ таким не исправимым, ну или там есть некий контекст все же, а не просто заявления в стиле "бегите глупцы" какими их обычно пытаются представить раст фанатики.

И в зависимостях зависимостей проверяете?)

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

это какие и в каких что их прям "не может быть"? утечка памяти и ресурсов в целом в языка с GC вроде как не уникальное явление, так же как и выход за границы, обращение к неинициализированным данным, дедлоки и всё остальное.

Например use after free. Пропробуйте вызвать такую ошибку в C-Sharp или Java. Да и в Go врядли удастся.

Ну а уж UB при переполнении signed int я больше нигде не видел.

а в C++ какое то необычное падение и стектрейсы? или оно в случае ошибки берет и сносит ОС? если мы конечно сравниваем языки в одинаковых задачах

В С++ выход за границы массива в лучшем случае вызовет segfault, который расследовать несопоставимо сложнее, чем нормальную текстовую ошибку + стектрейс.

В худшем случае это запортит очень важные данные, которые запишутся в БД, или приведут к уязвимости и взлому. Или к гейзенбагу.

конечно аргумент ведь зачем они тратят усилия на всё это если cчитают C++ таким не исправимым, ну или там есть некий контекст все же, а не просто заявления в стиле "бегите глупцы"

Они считают что нужно поддерживать легаси код, но не рекомендуют писать новый на С++.
Вы можете с этим не соглашаться, но странно делать вид, что этих заявлений не было. Вот например от АНБ
https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI_SOFTWARE_MEMORY_SAFETY.PDF

ну предположим нельзя, хотя мне кажется можно найти нетривиальные кейсы когда CSharp взаимодействует с какими ни будь ресурсами типа COM, но ценой чего? добавления GC? потерями перфоманса или часовыми плясками во круг borrow checker чтоб он соизволил понять что тут всё нормально?

а что собственно страшного в переполнении signed int и в чем принципиальное отличие от того что в других языках оно defined behavior хотя и делает тоже самое? я видимо просто не работал там где это критичная проблема хотелось бы понять проблематику, а то столько раз уже про это слышал но не разу не видел

вот уж чьё мнение меня меньше всего интересует в вопросах "безопасности кода" так это агентства по слежке и созданию 0 day уязвимостей везде где сможет дотянутся.

В худшем случае это запортит очень важные данные,

в других языках же такого не бывает совсем, привет от Log4j. Но почему то все критически важные узлы чувствительные ко взлому и отказоустойчивости всё равно пишутся на C и С++

ну предположим нельзя но, хотя мне кажется можно найти нетривиальные кейсы когда CSharp взаимодействует с какими ни будь ресурсами типа COM, но ценой чего? добавления GC? потерями перфоманса или часовыми плясками во круг borrow checker чтоб он соизволил понять что тут всё нормально?

Вы уж определитесь, GC или borrow checker.
Современные GC собирают очень шустро и могут не останавливать потоки для своей работы. Для абсолютного большинства задач это подходит.

Если вам не нравится GC и Rust, выбор довольно мал. Возьмите Zig.

а что собственно страшного в переполнении signed int и в чем принципиальное отличие от того что в других языках оно defined behavior хотя и делает тоже самое?

Конкретно в переполнении ничего страшного. Страшно что это UB, а любое UB может сломать программу максимально странным способом: например конечный цикл может стать бесконечным!
Тут есть и другие примеры:
https://github.com/Nekrolm/ubbook/blob/master/numeric/overflow.md

вот уж чьё мнение меня меньше всего интересует в вопросах "безопасности кода" так это агентства по слежке и созданию 0 day уязвимостей везде где сможет дотянутся.

Мнение Microsoft и Android (Google) для вас тоже ничего не значит? А как насчет Линуса Торвальдса?

в других языках же такого не бывает совсем, привет от Log4j. Но почему то все критически важные узлы чувствительные ко взлому и отказоустойчивости всё равно пишутся на C и С++

Они пишутся по:
1) Историческим причинам
2) Требованиям к FFI: библиотеку должно быть легко подключить к любому языку, так что С, но не С++
3) Требованиям к памяти: нужно гарантировать, что память в памяти не останется важной информации после освобождения объекта

Но процесс идет, и например Android переписывает кучу своего кода с С и С++ на Kotlin и Java, а небольшие критичные куски на Rust.

например конечный цикл может стать бесконечным!

Прикольно. А почему так происходит?

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

Компилятор переносит умножение на 0x20000001 на строку выше. Результат умножения оказывается больше чем int max, и он выкидывает условие остановки цикла.

Вы уж определитесь, GC или borrow checker.

Аксиома Эскобара

Возьмите Zig.

мм, язык с 40 летним опытом, кучей тулинга, комунити, десятками ide или же язык не выбравшийся из пеленок, хмм, ну выбор очевидный конечно)..

Страшно что это UB,

меня мало интересуют синтетические примеры, можно пример из жизни вот у нас оказалось переполнение и все взорвалось? А бесконечные циклы и без переполнения знаковых могут случится и не только в С++, детектится это на раз два по дампу или профайлеру, да и отлавливается ещё на этапе статических анализаторов обычно.

Мнение Microsoft и Android (Google) для вас тоже ничего не значит? А как насчет Линуса Торвальдса?

Линуса значит, вот только то что он согласился на поддержку раста как языка для драйверов ни какого отношения к "не безопасности" C++ не имеет, и его претензии к плюсам в целом мне понятны и в большинстве своём обоснованы , но они опять же ни как не связаны с "не бесопасным кодом"

так что С, но не С++

ты же знаешь что glibc в андроиде на C++ написан? и то что не проблема писать на С++ и иметь при этом внешний апи на C?

Но процесс идет

ну это только время покажет, эти мантры уже были за последние 30 лет и не раз так что очень слабо верится что что то изменится

Вы спрашивали:

а что собственно страшного в переполнении signed int и в чем принципиальное отличие от того что в других языках оно defined behavior хотя и делает тоже самое?

А теперь заявляете:

меня мало интересуют синтетические примеры

Похоже вы не читали другие примеры по ссылке. Вычисление хэша строки тоже синтетический пример?

Ну а в реальной жизни полно уязвимостей, вызванных UB переполнения int, раздел Observed Examples
https://cwe.mitre.org/data/definitions/190.html

А бесконечные циклы и без переполнения знаковых могут случится и не только в С++

В других языках эти ошибки будет легко воспроизвести и поправить код. А в C и С++ UB приведет к гейзенбагу, который будет наблюдаться раз в год при определенном положении Марса в созведии Козерога.

Линуса значит, вот только то что он согласился на поддержку раста как языка для драйверов ни какого отношения к "не безопасности" C++ не имеет, и его претензии к плюсам в целом мне понятны и в большинстве своём обоснованы , но они опять же ни как не связаны с "не бесопасным кодом"

Речь вообще не про Rust. Его претензии к С++ и С привели к появлению опций в gcc, чтобы можно было отключить некоторые UB ключем компиляции.
Ну а про Microsoft и Google вы совершенно случайно забыли ответить.

ты же знаешь что glibc в андроиде на C++ написан? и то что не проблема писать на С++ и иметь при этом внешний апи на C?

Если вот эта, то там от С++ одно название.
https://ru.wikipedia.org/wiki/Bionic_(библиотека)

ну это только время покажет, эти мантры уже были за последние 30 лет и не раз так что очень слабо верится что что то изменится

Очнитесь и выгляньте наконец в реальный мир. Он совсем не такой как в 2000 году:

Cloudflare целиком на Rust переписались, в исходниках Android его уже столько же, сколько C, AWS несколько сервисов целиком переписали и не останавливаются (и сделали Firecracker целиком на нем, опенсорс менеджер микровиртуалок, на котором работают Lambda и Fargate), с голенга многие тоже переписываются. Я могу дать полный список известных мне проектов, там от MESA до Figma, Vercel и части бэка npm.js репозитория

А бесконечные циклы и без переполнения знаковых могут случится и не только в С++

Например, в Фортране не может случиться неумышленный бесконечный цикл (хотя там есть специальный оператор бесконечного цикла). Там дело начинается с того, что в преамбуле вычисляется количество повторений цикла, и ровно столько оборотов он и делает, как бы ни изменялась управляющая переменная.

НЛО прилетело и опубликовало эту надпись здесь

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

А мне легко. Просто зависимость лежит в dll, которая предоставляется ОС, или хуже того вендором. И попробуйте туда внедрить санитайзер.

И мы возвращаемся к тому, что вам надо пройти по всему дереву зависимостей и все их перекомпилировать с санитайзерами и другими защитами. И надеяться что ничего не сломается.
В моем текущем проекте например 11 прямых зависимостей и 312 всего, нереально.

и как тут поможет любой другой язык в такой ситуации и в чем тут вина с++?

если вам нужно делать что то большее чем добавить пару флагов для сборки в каком ни будь текстовом файлике то у вас большие проблемы с CI.

Это мы уже обсудили:

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

И это будет работать для всего дерева зависимостей, кроме тех которые обертки над С библиотеками.
При этом в большинстве проектов вообще не будет зависимостей от С библиотек.

Просто зависимость лежит в dll, которая предоставляется ОС, или хуже того вендором.

А как в ней "грепнуть по unsafe" ?

Если вы перечитаете ветку, то мы обсуждали в основном языки с GC. Кроме того речь шла про санитайзеры, причем тут вообще unsafe?

Конкретно в Rust компиляция всего дерева зависимостей идет из исходников со статической линковкой. И cargo build вам выкачает всё дерево зависимостей, грепайте.

Если же dll это обертка над С или С++, или от вендора, то в ней по определению нечего "грепнуть по unsafe", ведь в С++ никакого unsafe нет.

Лучше вы сами внимательно перечитайте. В ветке было про сборку раст и с++.

В чем проблема в С++ делать компиляцию всего дерева из исходников со статической линковкой и нужными флагами санитайзера?

И они рекомендуют переходить на более безопасные языки в целом, а не только на Rust .

Я так понимаю ошибок в 3rd-party на других языках ни когда не бывает? или к чему это?

утечка памяти и ресурсов в целом в языка с GC вроде как не уникальное явление

Перечитал. Не согласен.

В чем проблема в С++ делать компиляцию всего дерева из исходников со статической линковкой и нужными флагами санитайзера?

Ага, бороться с зоопарком систем сборки, когда половина зависимостей настроена на динамическую линковку. Реально, но очень долго.

И все же что вы будете делать с dll от вендора?

Перечитал. Не согласен.

Читайте еще раз. Вы привели одну фразу про ГЦ, и пол фразы про другие языки. Одна цитата как раз про контроль качества зависимостей.

Даже если бы в ветке было бы в основном про гц, в чем проблема ответить на ту часть сообщение которую я считаю нужным прокоментировать?

Ага, бороться с зоопарком систем сборки, когда половина зависимостей настроена на динамическую линковку. Реально, но очень долго.

Не знаю о чём вы, у меня такого нету.

И все же что вы будете делать с dll от вендора?

Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?

Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.

И прочитал еще раз. И все-равно мы там обсуждали "другие языки" и GC последние 6 сообщений как минимум.

Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.

Разумеется можно:

crate-type = ["dylib", "rlib"]

Будет .so библиотека с кодом Rust без всякого C-API. И для вендоров всё хорошо.

Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?

В dll от вендора на практически любом языке не получится добавить санитайзеры, исходного когда тоже нет.
Так что придется поверить вендору что с ней всё хорошо. И полагаться на гарантии компилятора.
Например для CSharp я уверен что dll не портит память и не вызовет UB. Для Rust аналогично, если вендор мне ответит что там нет unsafe (разумеется если он не врет).

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Компилятор C++ (и даже C) с хоть на что-то годным оптимизатором требует от разработчика куда большего: понимать, что может привести к валидно компилирующемуся но не ведущему себя некорректно коду, а тоже держать в голове то, что не допускает такого поведения в его коде.

НЛО прилетело и опубликовало эту надпись здесь

Греп ничего не даёт. Инвариант необходимый для ансейф блока зачастую приходит снаружи

НЛО прилетело и опубликовало эту надпись здесь

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

НЛО прилетело и опубликовало эту надпись здесь

В стд есть проблемы с тем что им приходится писать везде __ чтобы не было конфликта с пользовательскими макросами. Это сигнал о том что разработчики стандартной библиотеки просто себя не уважают. А нам этот мусор ещё и читать приходится. Проблему с макросами можно было бы уже давно решить.
А концепты invocable или weakly_equality_comparable_with нёсут семантику, которая важна для логики программы. В то время как unsafe, unchecked, as mut T* с точки зрения логики програмы ничего не меняют. Просто вставляют азерты.

НЛО прилетело и опубликовало эту надпись здесь

Офигительно. А можно подробности?

какие?

НЛО прилетело и опубликовало эту надпись здесь

Там был локфри ринг буффер. С mmap, futex, поинтерами и подобным плотным взаимодействием с линукс апи. Прототип на си говорит получился понятнее.

НЛО прилетело и опубликовало эту надпись здесь

Все утечки, грепая по unsafe не найти. В расте утечка - это safe, и никто вам не запрещает Box::leak или что-нибудь посложнее в safe-подмножестве языка сделать без единой строчки unsafe у себя.

Есть большая разница: утечка из-за ошибки в коде (в unsafe) и сознательно вызванная утечка через Box::leak. Почитайте документацию:

This function is mainly useful for data that lives for the remainder of the program’s life.


Box::leak не приведет к use after free, double free и т.д. Потому что гарантии borrow checker никуда не деваются, и после выхода этой ссылки из области видимости вы уже не сможете к ней обратиться.

НЛО прилетело и опубликовало эту надпись здесь

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

RTTI реализован так, что действия с самим объектом в большинстве случаев его не трогает. Это как раз в Java есть постоянная работа в фоне с RTTI.

Если к объекту нет обращений чем виртуальный интерфейс, dynamic_cast или нет обращений к виртуальному базовому классу - ничего не происходит.

У тривиальных типов со стандартной моделью памяти RTTI отсутствует.

Это избавляет от необходимости писать весь этот код для самописных контейнеров

кого избавляет, разработчика стандартной либы? Давайте будем честны, мы чаще используем контейнеры, чем пишем свои. Я не против внешних универсальных функций, но почему бы их не продублировать в стандартных контейнерах?

Just use c++20 and requires

согласен, выше по коментам уже указали на этот косяк статьи. Однако все равно SFINAE с нами, и я считаю это одним из самых плохих архитектурных решений что я видел

Нельзя.

можно. Например, передав заранее счетчик ссылок до работы конструктора

Проблема-то где?

вот здесь: "Ну да, это приходится писать "

Дебаггер только чутка тупой

:))))

Потму что ваши методы не должны принимать контейнеры, а должны принимать ренжи. Если код использующий контейнеры дженерик, то надо через algorithm работать

Однако код"abrakadabra" == "abrakadabra"вернет false, ведь это два разных массива, их адреса конечно же не равны.

Результат "abrakadabra" == "abrakadabra" формально не определён, но на практике в любом вменяемом компиляторе будет равен 1, так как дублировать константу нет никакого резона.

std::string нельзя сделать строками по-умолчанию в С++ не только из-за обратной совместимости, но и потому что он использует динамическую память, и вообще его поведение недостаточно прозрачное и низкоуровневое для некоторых приложений, в частности для программирования микроконтроллеров с малым объёмом оперативной памяти, где динамическое освобождение памяти часто недопустимо. Возможно, стоило бы облегчить использование std::string, добавив специальный формат строковых литералов, например 'строка' вместо "строка". А код"abrakadabra" == "abrakadabra"во многих случаях вернет true из-за объединения одинаковых строк компилятором и линкером, хоть это и UB.

добавив специальный формат строковых литералов

Есть уже 10 лет как. Пользовательские литералы объявлены в стандартной библиотеке и "abrakadabra"s это std::string, если есть соответствующий using.

https://en.cppreference.com/w/cpp/string/basic_string/operator""s

Если с этим всё хорошо, чем же тогда недоволен @anz ?

тем что нужно использовать литерал. А к литералу еще и using

Вообще уже довольно давно существует std::string_view - являющйся по сути полным эквивалентом char *, но в то-же время являющийся классом. Но и с ним, есть проблеммы...

Можете пояснить, что именно является UB? Сравнение 2ух строковых литералов на C++?

Как я понимаю может быть либо true, либо false. Откуда UB?

Можете пояснить, что именно является UB?

Три компилятора говорят о том, что это совсем не то UB (unspecified).

Многие компиляторы могут делать одинаковые строковые константы одной константой, делая одинаковыми все ссылки на неё. Это делается в первую очередь для экономии памяти. Такая оптимизация включается и отключается специальной опцией компиляции. То есть по тексту программы нельзя сказать, будет ли результат true или false - это зависит от применяемого компилятора и его опций.

С одной стороны это хорошо, ведь это можно эффективно использовать как ключ с эффективным сравнением - нам не нужно проверять две строки посимвольно, достаточно сравнить указатель.

ну, вообще-то нет...

В целом горячо согласен, особенно про нестандартную Стандартную библиотеку. Руки бы за неё вырвать.

Но вот про строки согласиться не могу. Во-первых, язык, в котором "abracadabra" превращается в экземпляр string должен постесняться использовать букву C в названии (C#? Ну хорошо: язык без виртуальной машины). Во-вторых, это поощряет конкатенацию. А зачем? Нам нужно больше форматирования (конкатенации приводят к ужасающим ошибкам, самая очевидная из которых — внезапная невозможность локализации в культуру с необычными, или просто неанглийскими, грамматиками). В-третьих, это вообще поощряет использование строковых литералов. Это хорошо в хелло-ворлдах, но ужасно в промышленном коде. Ресурсы! Только ресурсы!

(Помню один проект, где использовался макрос _S(). Разумеется, пустой. Самописный препроцессор вытаскивал все литералы, сводил их в таблицу, потом был GUI-тул для правок… генератор локализованных бранчей… короче, много всякой наркомании. Вот что бывает, когда не осилил StringTable. Компания, между прочим, очень крупная и широко известная в узких кругах).

Помню один проект, где использовался макрос _S(). Разумеется, пустой. Самописный препроцессор вытаскивал ...

Нечто похожее есть в UnrealEngine. Там есть кучка пустых макросов, типаUCLASS, USTRUCT, GENERATED_BODY, которые предназначены исключительно для поедания отдельным инструментом под названием Unreal Header Tool, написанным, к слову, на C-sharp. Он по ним еще кучу С++ кода генерирует, который GUI рисует, позволяет взаимодействовать со сборщиком мусора, Blueprint Editor-ом и т.п.

Ну и в плюс кисходному топику. В том же UE есть своя "стандартная" библиотека, частично оборачивающая функции из STDlib - видать не хватает стандартной.

(любопытно, а почему не получается вставить символ решетки)

В этом может быть какой-то смысл. А вот использовать исходный код как первичку для локализуемых текстов… Раскидывать их повсюду, чтобы потом тулзой собирать… Вообще, я заметил, многие не врубаются в идею изолированных ресурсов. Даже великий (кроме шуток) Эрик Липперт.

D UE это не для локализации. Это для визуального проектирования и генерации кода с сохранением привязки к ключевым вещам. Изолированные ресурсы падают лицом в грязь как только встает проблема переносимости или смены версий.

Даже в Qt есть такая проблема и в результат все средства были выкинуты на помойку и теперь библиотека требует чтобы исходный код со строковыми константами был в Unicode. И исходник используется в качестве первички для создания "изолированного ресурса" словаря.

Это, кстати, интересный вопрос. Какие есть варианты создания кросс-платформенных ресурсов в проектах на C++? Чтобы они компилировались (по типу .rc → .res → .dll) и универсально грузились. Всякие диалоги, понятно, не нужны, т.к. сильно зависят от ОС или UI-движка, но разные картинки, HTML, таблицы строк, юникодные тексты и т.п. очень даже универсально востребованы. Да хотя бы вот, Доксиджен после обработки во что собрать? Чтобы одним файлом (и это был НЕ гигантский HTML с инлайновой графикой :).

Я согласен с автором, что астрокомитет занимается чем угодно, кроме того, что нужно в реальной жизни, так что вся надежда на опенсорс.

Для обертки в UE те же причины что и у QT - не все целевые платформы имеют все в реализации.

Вот что бывает, когда не осилил StringTable.

А можете пояснить как совместить StringTable с модульностью?
Если выносить всё строки в ресурсы то становится недостаточно включить/исключить заголовочный файл, надо ещё где то хранить список строк этого модуля и добавлять/удалять их в ресурсах.

PS: это не возражение - реально пробую осилить StringTable.

Буду рад поделиться своим скромным опытом.

Есть StringTable как Идея из платонова царства (именно её я и имел в виду). А есть несовершенные приближения конкретные реализации идеи StringTable — например, дотнетная или винапишная. Видимо, об опыте борьбы с этой последней и стоит рассказать.

У нас было два пакетика травы два модуля на C++, модуль с бизнес-логикой на Delphi и само приложение тоже на C++. (Связывалось всё через COM). Это, КМК, наиболее общий случай «сборной солянки». Мы создали пустую dll'ку (без кода), и все ресурсы, включая таблицу строк, добавляли строго туда. Потому что resource hell, с которым я столкнулся на предыдущем проекте, требовал нормализации.

(Вообще, dll — неплохой контейнер, если писать строго под винды. В WinAPI есть весь набор функций по работе с вложенными в него ресурсами и файлами, а ещё в виндах есть протокол res://, и все, кто в него умеет, работают с содержимым dll как с обычной папкой. Можно, например, упаковать туда целый сайт со справкой в HTML).

В проекте этой бескодовой dll был rc-файл (и отдельными файлами — все включённые в него внешние ресурсы) и соответствующий ему хедер. Тут возникает первая проблема: их надо всё время синхронизировать и исключить коллизии. Да, это проблема. Но это проблема не StringTable как Идеи, это проблема студии как инструмента. Она не поддерживает сквозную нумерацию, aka autoincrement unique (для этого надо последнее число хранить отдельно, а не рассчитывать его на основании имеющихся), и она не поддерживает автоматическое удаление записи #define IDS_ANSWER_TO_THE_ULTIMATE_QUESTION 42 из хедера при удалении соответствующей строки из .rc. Решение? Надо не полагаться на сломанный WYSIWYG-инструмент (редактор ресурсов), а работать с обоими файлами через редактор текста.

После компиляции мы получаем dll + хедер к ней для загрузки строк и других ресурсов. Порядок сборки гарантирует, что ресурсная dll'ка соберётся первой и будет положена куда надо (в папку с exe'шником), а хедер легко расшаривается между С++-проектами просто как файл.

Хуже всего, конечно, было дельфишнику, который не мог просто включить сиплюсплюсный хедер в проект (из-за разницы в синтаксисе) и ему надо было в pre-build steps конвертировать его в паскалевский файл (это тривиально).

В итоге — полное отсутствие resource hell (включая сюда гарантии, что у тебя абсолютно точно нет дубликатов или нелокализованных строк), встроенная локализация и мегаудобное сопровождение (двадцать лет спустя я безо всяких исходников беру простой Resource Hacker и смотрю фрагменты HTML, которые когда-то использовал, или могу что-то исправить для конкретной площадки).

На примере винапишного StringTable я, КМК, показал, какими принципами мы руководствовались. А что сейчас в этих же целях имеется для кросс-платформы, и имеется ли что-нибудь вообще, или надо ручками писать — самому интересно. Но я лучше напишу ручками загрузку ресурсов из контейнера, чем буду иметь дело с окрошкой из кода и данных.

необходимость передачи .begin()/.end() в большинстве случаев.

std::ranges::find_if(vec, ...)

и другие функции в std::ranges:: хедера <algorithm> решают эту проблему.

Но вот про extension methods согласен частично, ибо возможность сломать что-либо всё же присутствует, хотя это можно решить через добавление в стандарт чего-то вроде using-ов по типу того, как это происходит со строковыми и числовыми литералами. Тут мне нравится предложенное кем-то использование через оператор ".*", но странно, что его так и не приняли в стандарт. Ну, если писать свою библиотеку, то можно попробовать перегрузить оператор "->*" в качестве замены (всё равно по назначению его никто не перегружает), но проблему уже имеющегося кода это не решит.

Про модули и requires уже написали, так что распинаться не буду.

Их относительно легко использовать, особенно если использовать литералы.

Ну, тут немного моей личной фантазии, но если бы в c++ были бы shared immutable-строки как во многих языках на уровне хотя бы библиотеки, это было бы довольно хорошим решением, ибо можно было бы на constexpr-уровне сделать что-то вроде ""sv, но с возможностью конкатенации и другими плюшками.

Ну а так, лучше всего всегда писать ""sv тли ""s по ситуации. Но вообще, проблема первого в том, что операции конкатенауии и подобного недоступны, а воорого в том, что он всегда аллоцирующий.

Можно, конечно, написать нечто вроде ""s + "..."sv + some_fun(), но это не совсем то.

Ну или, к примеру, условно:

constinit static s = "abc"sv;
s+= "def"

Не откомпилируется

НЛО прилетело и опубликовало эту надпись здесь

shared immutable строки в C++ это разве не std::string_view?

Нет, так как он не продлевает время жизни строки. Эквивалентом является std::shared_ptr<const std::string>. В расте, например, есть Cow<T> для таких случаев.

А, я думал вам от строковой константы надо. Если от динамического источника, то да, увы.

Для поиска в данном конкретном примере можно пойти ещё дальше, и использовать find и проекцию:

std::ranges::find(myVec, tag, &GameObject::myTag);

А что, там не опций какой вариант стандарта использовать при компиляции? Для старых проектов один, для новых - другой?

У некоторых перечисленных проблем - есть решения. Ну типа как с инклудами и c++20 стандартом. Ну или например:

А если в конструкторе нужно создать некую древовидную структуру родитель-ребенок, где дети хранят слабую ссылку на родителя?

Для этого наследуемся от : std::enable_shared_from_this. Внутри вызываем shared_from_this. Вопрос лаконичности - тут субъективно. Но то, что нужно делать дополнительные телодвижения для типовых ситуаций - это факт.

Вы сначало напишите тестовое приложение по вашей идее а уже потом советуйте. Шаред фром зис НЕ решает проблемы получения шаред указателя в конструкторе. Я вам по секрету скажу у этой проблемы НЕТ решения если есть требование использовать стд шаред поинтер. Если свой шаред поинтер написать то можно решить эту проблему, но со стандартным никак.

Согласен. Упустил тот факт, что речь о конструкторе.

В случае с геттерами, сеттерами. Их не нужно городить в каждом классе. Они нужны только для того, что если у вас в классе должен сохраняться инвариант, и чтобы пользователь не мог его нарушить. А теперь такой вопрос, какой инвариант может нарушиться если мы доступ к position сделаем public? Что можно сломать? И зачем тогда нужны методы get/set?

Что можно сломать?

Например, запихать NaN.

Вы для всех float делаете проверку на NaN?

Я вообще не понял как вы сэкстраполировали мой комментарий до такого абсолюта.

Польза от них в том, что можно поставить breakpoint и ловить использования/присваивания.

В современных IDE можно поставить дата брейк на любую нужную переменную.

Скажу страшную вещь, лично я включаемое пользователем исключительное состояние по доступу к переменной первый раз увидел в императивном как доска языке PL/I в 1989 году.

Это не эквивалентно. Дата-брейкпоинты полезны чтобы поймать изменение конкретной переменной/поля. Брейкпоинт в сеттере позволяет поймать изменение этого поля в любой структуре. В зависимости от ситуации может быть нужно как одно так и другое.