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

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

Другие библиотеки, такие как Boost, облегчают работу с BLAS-функциями (например, точечными продуктами

Серьезно?

Тот редкий случай, когда google translate справился бы лучше.

Я пошел в комменты чтобы найти этот комментарий.

C++ -- ужасный язык. Проблемы в статье высосаны из пальца. А вот его реальные проблемы:

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

  2. Нет единого формата пакета. Из-за этого бардак с пакетными менеджерами. Есть conan, гвоздями прибитый к python со своими тараканами. Есть vcpkg, который работает далеко не везде и не со всеми библиотеками и выглядит сырым. И так далее. Отсутствие пакетного менеджера в 2021 -- это само по себе неудобно.

  3. Тяжёлое наследие Си -- #include, макросы, разделение на хедеры и сорцы (пофикшено частично).

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

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

брать пример с развития Раста, создатели которого заранее подумали об экосистеме и сделали её удобной

Ну таки Раст относительно новый язык, вот и сделали сходу по-современному

Отсутствие пакетного менеджера в 2021 -- это само по себе неудобно.

То то мы уже год как переехали на тот самый сырой и... отсутствующий(?) vcpkg и счастливы.

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

Покажите мне хоть один мало-мальски крупный C++ проект на github, где можно было бы просто сделать git clone, а потом собрать одной командой.
Никогда и ничего не соберётся с первого раза. Да, даже если дословно выполнить те 10 страниц инструкции по сборке, которые там в readme.
Как-то в XXI веке хочется, чтобы такая инструкция была записана как минимум в виде стабильно работающего скрипта (а лучше вообще декларативно), а все зависимости подтянулись автоматически прямо в процессе сборки.

Покажите мне хоть один мало-мальски крупный C++ проект на github, где можно было бы просто сделать git clone, а потом собрать одной командой.

Собственно, именно это я у себя в проекте на работе и сделал. Билд 1 кнопкой с автоподтягиванием и автообновлением\пересборкой зависимостей и проекта при изменениях. Знаете, сколько это заняло строчек кода?

В районе 15 строк на повершелле, и 10 строк на MSBuild. Почему люди с гитхаба не хотят\могут это сделать - вопросы к ним.

НЛО прилетело и опубликовало эту надпись здесь
cmake --build . --config Release

Или по кнопке в Visual Studio.

Под капотом подтянется vcpkg (git submodule), который соберёт все 100+ зависимостей.

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

Бинарники vcpkg не тащит, такое умеет conan. Пакетные менеджеры будут использовать тот компилятор, который вы им укажете.

Как уже заметили выше, toolchain можно подсунуть свой. Бинарники после сборки кешируются.
Как я понял, по задумке Microsoft vcpkg будет встроен прямо в Visual Studio, а пользователи будут пользоваться vcpkg registries, но пока это только планы.
PS: с Linux всё немного интереснее из-за того, что библиотеки в папке с исполняемым файлом имеют приоритет ниже, чем системные, но это удалось побороть, подсунув $ORIGIN в rpath.

Есть такой проект: OBS.

Unreal Engine 4/5

Собирается с первого раза, без плясок с бубном

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

Ну да... обычно, при переходе в другую команду, со старым плюсовым проектом, первое задание, зачастую на несколько дней - скомпилить проджект. Часто это заканчивалось тем, что сидели и компилили всей командой. "Главное один раз сбилдить, а потом главное не удаляй статические либы.. ибо заново". Еще когда-то был случай когда в процессе "разработки" каким-то хреном добавили кросс-зависимость между двумя библиотеками. И получилось, что А не билдится без Б, а Б не билдится без А... В том же .net, такой проблемы не может быть по определению..

Никогда и ничего не соберётся с первого раза.

Но это же очевидная ложь.

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

Да-да, vcpkg такой классный, что не давал выбрать версию пакета год назад:

https://github.com/microsoft/vcpkg/issues/1681

А сейчас даёт? Как может быть менеджер пакета без возможности установки точной версии, когда речь идёт о сложном проекте?

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

1. Не понял суть претензии. То есть я верю, что для вас это проблема, но вот я уже больше 10 лет профессионально программирую на С++, и не только не испытывал такой проблемы, но даже плохо понимаю, в чем она заключается.
3. Разделение на хедеры и сорцы — это гениально. .cpp и хедер — это как книга и её оглавление. Очень удобно и полезно.
3. Разделение на хедеры и сорцы — это гениально. .cpp и хедер — это как книга и её оглавление. Очень удобно и полезно.

А чем это хорошо? Из-за шаблонов мифическое ускорение компиляции за счёт параллелизма несколько нивелируется, а редактировать объявление и реализацию синхронно — неудобно и способствует внесению ошибок.

Именно тем же удобно, чем удобно иметь оглавление к книге. Быстрая навигация по коду, лекго окинуть взглядом весь класс. А ошибки несоответствия объявления и определения компилятор легко и сразу выявляет, анализатор реального времени в IDE тоже.
Быстрая навигация по коду

Это ортогонально делению.


лекго окинуть взглядом весь класс.

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

люди так устали от ввода numpy, что все коллективно решили импортировать его как np

Дело не только и не столько во вводе, сколько в чтении. Особенно если numpy встречается несколько раз в одной строке

Миф 4 - плохой пример

    auto x = 1;
    x = 4294967294; // чему тут x равно теперь?

    return 0;

не надо так auto использовать

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

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

Я вообще против выведения типов - такой код плохо читается.

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

Лямбда не называема? Разве для лямбд не работают те же принципы именования что и указателей на функцию? Или я что-то не понял?
Ну мне например, легче читать код где явно указан тип. Потому что вот у вас есть авто и инициализируеться через функцию, которая неясно что возвращает, неясно откуда импортируется и что делает? Как понять что происходит в коде? Надо ради понимания 40 строк кода, надо еще 4000 строк внешних зависимостей читать.

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

Если я читаю код не в VS, а, например, текстовом редакторе, то мне важно видеть тип данных. Откуда я знаю, что это тип Child? Или может там обертка какая-то используется? В противном случае необходимо смотреть кто что выдает и что куда принимает, читать код с auto очень тяжело. В чем проблема прописывать тип данных?

мне важно видеть тип данных

Зачем? Что даст эта информация при чтении примера?
Эта необходимость появится при изучении кишков HandleChild, где в объявлении будет все необходимое в явном виде.

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

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

Как вы с полиморфным кодом справляетесь?

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

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

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

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

Как вы с полиморфным кодом справляетесь?

Как вы с полиморфным кодом справляетесь?

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

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

Если можно писать не полиморфно, то лучше писать не полиморфно.

Наоборот же) Не полиморфно можно писать всегда, но для копипасты должно быть какое-то здравое обоснование.

Вполне можно обойтись без копипасты и без полиморфизма.

Мне сложно представить, за исключением случая повсеместного использования паттернов, ситуацию когда нужно прям очень много полиморфных классов, ну скажем больше 5-10 разных интерфейсов на миллион строк кода

Статический полиморфизм: шаблоны, макросы, алгоритмы на void* — чуть более, чем везде. С динамическим их роднит главное: оказавшись внутри в отрыве от контекста нельзя точно узнать конкретные типы.
НЛО прилетело и опубликовало эту надпись здесь

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

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

Дело не в подсветке IDE. Чтобы понять смысл этого отрывка, знать типы совершенно не обязательно, выразительных средств языка и самоописывающих идентификаторов достаточно.

Потому что HandleChild может нечаянно неявно преобразовать тип, который вообще не ожидает , к типу который ему подходит.

Это как auto arr = {1,2,3}

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

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

Да, преобразования типов зло и лучше не делать. Но куча библиотек и Легаси кода , против этой замечательной практики.

Согласен, при оптимизации все выглядит неплохо.

Мне тоже кажется, что с типами лучше, чем с auto. Другое дело, что само имя контейнера как правило действительно не нужно. А вот лежащий в его основе тип еще как нужен. Было бы можно писать auto<Child>, было бы круто.

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

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

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

Мой поинт, если хотите, в том, что функции надо писать так, чтобы локальные типы были не нужны для человека.

Вы привели слишком простой пример. В реальности это может быть вектор из Child, вектор из Child*, вектор из smart_pointer<Child>, хуже того, это может быть вектор из пары <индекс в бд, Child>...

Вы так, во-первых, не вычислите тип возвращаемого значения

В заголовке лямбды его можно тоже указать

Где, в точке определения или использования?

В сигнатуре той функции, что принимает лямбду

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

Пока тип элемента, лежащего в контейнере, совпадает с типом,

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

А зачем в контексте данной дискуссии?

Потомучто можно вместо function темплейт тотже указать например. Или auto. Но зачем?

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

ну ругнётся компилятор

Компилятор ругнется через 40 минут после нажатия на кнопку build. А результат мне нужен сейчас.

детализированность сигнатуры функции вам вообще никак не поможет в точке её вызова,

Это по крайней мере на один хоп ближе к нахождению настоящего типа. К томуже в месте создания переменной ее вид также виден

НЛО прилетело и опубликовало эту надпись здесь
Хромуим с нуля может больше суток собираться, так что это не на столько не реалистично.
С нуля будут собирать только заведомо рабочий код.
Компилятор ругнется через 40 минут
Вы пытаетесь уйти от одной проблемы и тут же натыкаетесь на другую.

<source lang="cpp"> std::function<int(void)> lam = [&x] { return x;}; // для списка захвата

int (*lam)() = { return 20; }; // без списка захвата </source>

то зачем мне тут в теле типы? Что вам скажет, является ли children

Что за тип child? Это самостоятельный тип? Это интерфейс, за которым пачка классов, типа новорожденый, детсадовец, подросток? Я его впервые вижу вот - жамп ту дифинишен как выполнить?

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

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

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

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

В общем для встроенного софта иногда из за этого бывает больно.

Что написать вместо auto?

std::function<int(int)> l = [](int){ return 0; };

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

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

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

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

Ну сама фича то, огонь. Особенно когда длинующий шаблонный тип выводит, так вообще.

Просто, пользовать надо с умом, хотя это ко всему относится.

Какого типа будет x в данном примере? Я так понял auto это аналог dynamic из c#?

Нет, аналог var.

Понял, я написал раньше чем там писали потому не видел.

в C++ очень сложно сделать так, чтобы ваш код сделал нежелательные вещи

да ладно??

Автор (оригинала) видимо до STL еще не добрался, не удалял текущий итератор, не разыменовывал битый итератор, не забывал проверить итератор на end, не натыкался на виртуальные деструкторы, не забывал копирущий конструктор/оператор, не инициализировал члены класса не в том порядке, не забывал один из shared_ptr-ов сделать weak_ptr-ом, не передавал случайно здоровенный vector по значению, не забывал виртуально отнаследоваться, когда внезапно оба родителя имеют общего предка ...

Хотя это может просто у меня в свое время руки кривоваты были, не знаю.

бОльшая часть того, что вы написали - детектится Решарпером или clang-tidy.

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

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

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

Касательно мифа 1, мне кажется, что ценность shared_ptr для C++ сильно преувеличена. Сколько я ни сталкивался с использованием std::shared_ptr в нашей кодовой базе, его можно было (и стоило) заменить на std::unique_ptr

Неужели в вашем проекте на объекты нет более одной ссылки? В мало-мальских сложных проектах shared_ptr полезен.

shared_ptr это не про ссылки, а про управление временем жизни. Чаще всего при работе с объектом известно, что он будет существовать всё время вызова функции и не нужно забирать владение - в таком случае передача по ссылке работает прекрасно. Если нужно создать и вернуть объект единственному владельцу, то отлично работает unique_ptr . Для меня редкий сценарий, когда время жизни объекта неясно, нет одного объекта, определяющего время его жизни. Тогда да, shared_ptr уместен. Однако в моём случае такая потребность почти не возникает

.

Согласен с вами полностью. shared_ptr крайне полезен сам по себе, но очень «overused», «чрезмерно употреблен». Я вот вижу shared_ptr в коде (а у нас в проекте их все еще предостаточно) — сразу думаю «что-то тут не продумали с лайфтаймом/владением».

это правда, Страуструп по-моему тоже об этом писал (ссылку лень искать). Продуманное владение почти вытесняет shared_ptr, и более того, без продуманного владения shared_ptr не спасет, будут либо циклические ссылки все равно, либо weak_ptr-ы пустые тогда, когда объект еще нужен, и так далее. Однако shared_ptr нужен, если у вас многопоточка, и потоки друг другом не владеют и друг друга не ждут.

давно по этой статье выучил немного разобрался с С++
How to Program in C++ (fit.edu)

вот бы где так же сжато, без воды но учетом всего что добавлось за 20 лет.

Придя из Python, где люди так устали от ввода numpy, что все коллективно решили импортировать его как np
О, от того, как сейчас используют Python, у меня пригорает так, что я не просто улетаю в космос на собственной реактивной тяге, но ещё и врубаю гипердвигатель, переходя в гипербаттхертпространство.
Знаете, когда-то я думал, что в IT-природе не может существовать ничего худшего, чем PHP-говнокод, создаваемый провинциальными веб-студиями. Но потом в этот мир пришли Data Science и Machine Learning и пробили дно так, что снизу уже и стучать неоткуда.
Откройте любой Github-реп по ML (даже от крупных контор), где грузится и тренируется какая-нибудь нейросеть — и там под капотом будет просто лютейшая жесть, собранная из говна и палок, подпёртая костылями и перемотанная синей изолентой. Это просто рафинированный, эталонный говнокод, на который даже дышать страшно, чтоб там всё не посыпалось.
Тесты? Не, не слышали. Документация? В словаре нашего токенизатора нет такого слова. Системные требования? Ну, самая популярная тема для Issues в мире ML — «а сколько минимально надо VRAM, чтоб это запустить», потому что никто и никогда даже не скажет вам, какие нужно выделять ресурсы на запуск этих поделок.
Реально, всё ML производит впечатление студенческих наколеночных поделок. Причём созданных теми студентами, которые выучили Python две недели назад и не способны даже сделать pip freeze, чтобы сформировать нормальный requirements.txt. В каждом проекте хотя бы пару-тройку зависимостей туда добавить забудут, причём не тех, которые подтягиваются pip со стандартных репов, а кастомных, которые они с чужих github-репов накачали.

ML и разработка ПО - разные в реализации вещи. ML больше напоминает "научный подход" (т.е. принятый в научной среде) - "максимально быстро пробуем over 9000 вариантов, ненужные 8997 вариантов выбрасываем" (да, код написанный учёными - обычно такой). Разработка ПО, если это серьёзный проект, требует архитектуры, code style, комментов... Но если вы пытаетесь создать совершенно новый алгоритм для решения нерешённой людьми задачи - вероятно, вы скатитесь в перебор десятков-сотен вариантов алгоритма, и тут уже выгоднее быстро написанный говнокод.

Быть может, разработка ПО более изучена и в ней уже выработаны определенные правила хорошего тона, тогда как ML - область более молодая, и руководства в ней - скорее рецепты, чем алгоритмы. Быть может, в ML больше изменчивость кода во времени, и документация мгновенно устареет, а в разработке ПО из ТЗ сразу более-менее ясно, что должно быть, и можно успеть причесать код (это нужно делать в любом случае) до изменения требований.

Не каждому коду суждено жить долго. Часто он нужен "здесь и сейчас", чтобы завтра его выбросить на помойку (github, ага). Сейчас большая часть ML - это склеивание готовых компонентов на изоленту и матершину, чтобы сдать курсач или получить премию за прогрессивный и модный "мэшн лёнинг" в проекте. Для ML-моделей, которые в принципе "хз как работают, но, вроде, работают" очень гармонично подходит такого же качества код.

Согласитесь, "студентами, которые выучили Python две недели назад" - звучит как неслабая такая реклама Python? :)

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

Пока в проекте не появятся забористые циклические ссылки, которые не представляют проблем для gc и даже могут упрощать код (в таком случае есть просто ссылка на объект, нет вариантов из */&/weak_ptr/unique_ptr/shared_ptr/etc, нет конструкторов копирования/перемещения), но в языках без gc называются плохой архитектурой.

Упрощение кода как побочный результат подтирания задницы разработчику плохой архитектуры

В языках с gc также успешно все течет при кривых руках

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

Что вы имеете в виду под "гетерогенные ссылки"?

Когда ссылки образуют цикл, объединяющий значения разных типов

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

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

У меня две претензии к языку:

  • Сохранение "совместимости с C" в плане преобразования типов: сделать шаблон, надёжно различающий int, bool и поинтер - задача не тривиальная.

  • Передача "по ссылке" ни как не выделяется на стороне вызывающего. Если "ссылки" задумывались как "не NULL" поинтеры, то лучше было сохранить взятие адреса при передаче параметра.

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

> Передача "по ссылке" ни как не выделяется на стороне вызывающего.

Зачем её выделять?

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

> Если "ссылки" задумывались как "не NULL" поинтеры, то лучше было сохранить взятие адреса при передаче параметра.

Ссылки задумывались, чтобы можно было написать a + b независимо от того, являются ли эти термы интами, комплексными числами или вообще векторами в N-мерном пространстве с указателем на аллоцируемую в рантайме память под капотом.

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

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

Решарпер умеет такое подсказывать уже где-то год.

А причём тут решарпер и С++ ? Вы имели в виду Clion?

А когда diff просматриваете в GitHub/GitLab, вам решарпер поможет?

Решарпер и в плюсы умеет весьма неплохо. Только по моему опыту он достаточно сильно тормозит на больших проектах при выполнении некоторых задач.

Давно и прочно пишу на C++, но реально нравится явное использование ссылок на стороне вызывающего кода в rust. Иначе иногда непонятно может ли что-то поменяться или нет. А const не воспользоваться т.к с ним move-семантика не уживается

Не совсем. Если переменная передана как ссылка, то ссылку брать не требуется. Например, в таком примере

fn g2(i: &mut u8) {}

fn app(i: &mut u8) {
    let mut j = 5;
    g2(&mut j);
    g2(i);
}

Для переменной j ссылка нужна, для i уже нет.

Это конечно логично, потому что i это уже сама по себе ссылка, но просто читать код в надежде выцепить из него все &mut уже недостаточно, в результате приходится вглядываться в код также пристально, как и в c++

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

В новом стандарте сломан не сам C++. Его-то, как раз, более-менее починили.

Там сломано примерно всё остальное - весь код, который УЖЕ написан и его больно использовать, стандартная библиотека, культура и менеджер пакетов, культура разработки.

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

C++ простой и удобный язык который позволяет делать много прикольных вещей. Например:

Изменять "const" объекты:

static const std::string XXX("YYY");
// много строк кода
std::string* p = (std::string*)&XXX; // где-то, где очень надо
p->assign("ZZZ"); // и ведь поменяется

Создавать reference на nullptr:

object* pX = nullptr; // давным давно здесь был NULL :-)
// много строк кода
object& rX = *pX; // где-то далеко, возможно в другом файле
rX.foo(); // помрёт здесь, если создатель класса не маньяк

возвращать куски разрушенных объектов:

const char* foo()
{
	std::string s1;
  // много строк кода
  return s1.c_str(); // вернём указатель на кусок непонятно чего
}

Или присвоение в условном операторе:

if(x=y) // и ведь работает! только, как-то, странно :-)
{
	// здесь делаем что-то полезное
}

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

З.Ы. Это, если кто не понял, был сарказм после изучения репозитория на пару гигабайт С++ кода с давней историей, который успешно собирается и проходит тесты.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий