В частности, это не говорит о том, что популярность C++ падает. Вы сделали это утверждение, вам его и доказывать. Я этому подтверждений не нахожу.
Например вот эта статистика
Большая часть из этих репозиториев неактивны и не используются в реальных задачах. Значительная часть — наработки вкатунов и студентов, которые пробуют свои силы в новом языке. И там не учитываются размеры репозиториев — большие и маленькие репозитории вносят одинаковый вклад в статистику. Я не вижу причин считать эту статистику релевантной, и я не знаю способа адекватно измерить популярность языка, кроме опросов.
тут кто-то призывает отказаться от С++
Это спорная рекомендация, которая подвергается критике (например, здесь). Она смешивает C и C++, игнорируя, что C++ за последние 30 лет сильно улучшил memory-safety по сравнению с C — STL containers, smart pointers и т. д. (а в C++26 появился ещё и hardening стандартной библиотеки, который убирает множество случаев UB из-за невалидных итераторов, выходов за границы массива, запрещённых операций над контейнерами и пр.). Есть инструменты статического анализа, которые встраиваются в IDE и CI/CD-пайплайны и которые помогают писать безопасный код и не требуют для этого сложных действий. Нет смысла оценивать безопасность C++ отдельно от этих инструментов.
Вообще, нет смысла говорить, что один язык memory-safe, а другой нет. Нужно взять конкретный инструментарий для конкретного проекта, включая весь CI/CD пайплайн, и определить его степень memory safety. И окажется, что между современным C++ и тем же C# разница не такая значительная, как все привыкли думать. Перекрывает ли эта разница те преимущества C++, которые я перечислил в статье — это дело вкуса. Лично для меня — не перекрывает даже близко.
Ваш первый комментарий был чересчур эмоциональным и игнорировал текст статьи, поэтому я не видел смысла полностью на него отвечать. Вся критика строилась на отсутствии стандартизованных инструментов и сложности подключения библиотек (это единственные конкретные недостатки, на которые вы указали), но вы эти проблемы упомянули как-то вскользь, без должного объяснения. Притом что я эти проблемы в статье описал подробно — если вкратце, там говорится, что у С++ более фрагментированная экосистема, чем у C#, но в ней есть и стандартизация ABI в рамах каждой платформы, и пакетные менеджеры, пусть и не с такими обширными репозиториями.
Что вы все как заклинание повторяете эту заезженную мысль? Каждый второй комментатор, кажется, уже написал, что их нельзя сравнивать. Ну а я вот взял и сравнил. Получается, что можно.
Мне любопытно — там есть ещё что-нибудь, что выглядит смешно? Сама постановка вопроса "что лучше - с++ или c#", которая в среде айтишников считается чуть ли не табуированной — не кажется слишком смелой? Обещание окончательно ответить на этот "вечный вопрос" не кажется гротескно самоуверенным? Большая синяя кнопка "Объективное и беспристрастное сравнение" вместо "Читать далее" не наводит на мысли? То что я весь 1-й раздел описывал боль, связанную с разработкой на плюсах, а потом вывернул это как преимущество C++, потому что "настоящие хардкорные программисты любят, когда язык их всячески сношает и заставляет преодолевать трудности" — вам не показалось, что это с самого начала задаёт весь тон статьи? Вы не увидели долю самоиронии в том, что C++-программистам меньше платят, а я подаю это как преимущество C++? А фраза "я должен быть строг, но справедлив — формально рефлексия в C++ есть, и через несколько лет, когда её доделают, она будет лучше, чем в C#" — показалась вам абсолютно серьёзной?
Сравнение производительности — это отдельный труд и отдельная статья, на которую у меня уже нет ни времени, ни сил. Тема этой статьи задана в первом абзаце — удобство самого языка и инструментов. Статья и так получилась большая, и я уже разобрал в ней достаточно много вопросов.
Пожалуйста, пишите код единым блоком с указанием языка — на Хабре есть такая опция. С ней код получается компактным и с подсветкой синтаксиса.
Чтобы найти максимальный элемент, всё, что нужно — это либо оператор <, либо оператор >. Это логично, и это то, чего ожидает пользователь. Делать функцию max, которая требует оператор-, да ещё и explicit operator bool — это очень странный контракт, который вызовет недоумение у ревьюеров. Я даже не знаю, как прокомментировать этот код, чтобы меня не забанили. И почему в этих операторах b._value не проверяется на null?
Использование dynamic допускает любые операции без compile-time проверок. Обе реализации функции max из статьи во время компиляции выполняют проверку, что у типа есть нужный оператор. Причём этот контракт явно декларируется в объявлении функции max, и при его нарушении вы получите ошибку компиляции, которая чётко и ясно скажет вам, что здесь не так. На каком основании вы заявляете, что этот код "такой же, как и у меня"?
К чему там вообще ToString и operator+? Что вы ими хотели сказать?
И вы мне ещё объясняете, какой код "не пройдёт PR в нормальной команде". Да вы вообще имеете хоть какое-то отношение к IT?
Вы всерьёз собираетесь оспаривать, что возможности шаблонов на порядки шире, чем дженериков?
Как использовать max для типа, у которого определён только оператор <, либо не реализован интерфейс IComparisonOperators?
Зачем классам через интерфейсы сообщать о себе информацию, которая и так известна на этапе компиляции?
Потому что вы не рассказываете, а упомянули их как "не значащие", хотя на самом деле это единственный большой минус C# (точнее фреймворка), а остальным параметрам он просто наголову удобнее линковки в плюсах.
У меня весь первый раздел про то что C++ менее удобен в плане линковки, работы с зависимостями и в плане UB. С чем вы спорите?
То, что не понимаете как работает линковка в шарпе и какие минусы несёт в себе cmake
Где в статье я демонстрирую непонимание, как работает линковка в шарпе, и где — непонимание, какие минусы несёт CMake? Процитируйте оба места.
про dll hell вы предпочли не заметить
У вас плохая кратковременная память. Про dll hell вы написали в другом треде, и я ответил уточняющим вопросом.
Где это всё в моем и вашем примере?
В моём примере этого нет, тем он и прекрасен. В вашем:
используется массив object[], а массив в C# — это объект в куче.
Если в params передаются value types, то происходит их boxing при приведении к типу object:
for_each_arg(foo, 42);
в куче создаётся object, содержащий 42. Это ещё одна аллокация памяти в дополнение к массиву args.
Рантайм каст нужен в функции делегата Action, чтобы выполнить логику над конкретным типом. В C++ в этом месте используется перегрузка функций, которая разрешается в compile time.
потому взял ваш стиль, у вас вся статья такая
То есть я где-то в статье беру одну маленькую деталь, которую в худшем случае можно назвать неоднозначной, и из неё вывожу глобальное суждение о целой области? Или намеренно избегаю технических вопросов и перехожу на туманные формулировки и вкусовщину? Где именно я всё это делаю?
И миллионы строк кода написанного на шарпе - ну это просто все ошиблись.
А где я говорю, что писать на шарпе — это ошибка? Я вообще-то сам на нём пишу.
Просто купите более мощный комп, и проект, который собирался 4 часа, будет собираться всего за час. (если что, это сарказм, смешанный с самоиронией. Время компиляции в C++ действительно не радует)
Удобства встроенной библиотеки
В 7-м разделе статьи я подробно рассказал об "удобстве" контейнеров C# в сравнении с C++ и его итераторами.
Вы проигнорировали примерно половину моих вопросов. Спрошу ещё раз:
к чему была аналогия с Феррари, и какой тезис статьи она должна была опровергнуть?
зачем вы принялись рассказывать про бинарную несовместимость в C# и про непереносимость между ОС, притом что я сам рассказываю про эти проблемы буквально в том же предложении, которое вы цитируете?
Ответьте на них, пожалуйста, а то после таких возражений остаётся впечатление, что вы не читали статью, а просто скормили её LLM, и попросили написать комментарий.
абсолютно не объективно и уж тем более не беспристрастно
То есть вы на полном серьёзе обвиняете эту статью в отсутствии объективности? Чем больше я вас читаю, тем больше убеждаюсь, что разговариваю с роботом, который не видит общую картину текста и не понимает его общий настрой. Я даже не буду вас разубеждать или что-то подсказывать — просто дам совет сначала читать статью, а потом писать комментарии.
Так и основной вопрос - зачем? С учетом implicit\explicit можно возвращать bool
Если операторы сравнения для класса возвращают другой тип, конвертируемый в bool, то вы не сможете использовать его с функцией max — это просто не скомпилируется. std::convertible_to — это пример гибкости концептов. С их помощью можно задать любые требования к параметрам шаблона. Возможности шаблонов в C++ на порядки шире, чем возможности C# дженериков. Вы всерьёз собираетесь это оспаривать?
Покажите, как в C# можно использовать функцию max для типа, у которого определён только оператор <. Либо есть все 6 операторов, но не реализован интерфейс IComparisonOperators. Писать класс-обёртку, и в нём определять 6 операторов сравнения, 5 из которых вы никогда не будете использовать? Положа руку на сердце, вы считаете, что это пример хорошей архитектуры языка?
В C++ вы выражаете требования в концепте, который сам достаёт всю информацию о классах, без помощи интерфейсов. Если для класса определён оператор <, то концепт просто это видит. Зачем классам через интерфейсы сообщать о себе информацию, которая и так известна на этапе компиляции? Это просто нелогично, и это ограничивает ваши возможности.
Из всех преимуществ шаблонов, о которых я рассказал, вы выдернули один std::convertible_to<bool>, без которого операторы сравнения могут обойтись (ибо что ещё им возвращать кроме bool), и на основе этой мелкой детали сделали обобщённую оценку на весь раздел: "Вообще вся эта секция притянута за уши". Это приём из области демагогии.
Ну точно не для того примера, который вы привели.
А что меняется для этого примера? Массив params[] перестаёт выделять память в куче? Для значимых типов перестаёт использоваться boxing? Или куда-то пропадает рантайм каст к нужному типу? Я вижу, вы решили проигнорировать технические возражения, надеясь, что никто не заметит, и сосредоточиться на вкусовщине: "то есть в плюсах это выглядит красиво? Абсолютно не читаемо". Это опять демагогия. Да и что значит нечитаемо? Во-первых, вполне читаемо, во-вторых используется обычно для классов с простым и понятным назначением, вроде function или tuple, код которых никому и не надо читать. В C# для Func написано 17 реализаций с разным числом параметров, а для ValueTuple — 8 реализаций — вот это реально нечитаемо, и к тому же ограничено по числу параметров.
Опять - зачем?
А зачем запрещать? Программист сам может решить, что для его кода хорошо, а что плохо.
Плодить простыни кода?
Наоборот, чтобы сделать код более читаемым и не засорять внешнее пространство имён каким-то мелким служебным классом, который имеет смысл только внутри этой функции.
Я не умею спорить в общем и целом, только по конкретным пунктам. У меня в статье этих конкретных пунктов полно — берите любой и приводите контраргументы.
Вы на серьезных щах
Ну это перебор. Что не так с этими комментаторами?
сравниваете то, что сравнивать не нужно.
Возражение было бы релевантным, если бы я сравнивал C++ и Excel. То, что их не нужно сравнивать — это клише. У них сильно пересекаются возможности и области применения. И их регулярно сравнивают. Выйдет какая-нибудь сложная статья по плюсам, обязательно в комментариях появится какой-нибудь г-н "Я 10 лет назад перешёл с C++ на C#, и до сих пор радуюсь своему решению и охреневаю от того, как у вас всё сложно и неудобно". А я вот, представьте, охреневаю от того как в сишарп всё сложно и неудобно.
Аналогично каждый язык хорош в какой-то своей области
Я сравниваю не области применения, а заложенные в них архитектурные решения, концепции и идиомы, а также удобство экосистемы и инструментов. Удобно ли пользоваться системами сборки и пакетными менеджерами, насколько удачным решением был Nullable контекст, в каком языке обобщённое программирование даёт больше возможностей, и т. д.
В частности, это не говорит о том, что популярность C++ падает. Вы сделали это утверждение, вам его и доказывать. Я этому подтверждений не нахожу.
Большая часть из этих репозиториев неактивны и не используются в реальных задачах. Значительная часть — наработки вкатунов и студентов, которые пробуют свои силы в новом языке. И там не учитываются размеры репозиториев — большие и маленькие репозитории вносят одинаковый вклад в статистику. Я не вижу причин считать эту статистику релевантной, и я не знаю способа адекватно измерить популярность языка, кроме опросов.
Это спорная рекомендация, которая подвергается критике (например, здесь). Она смешивает C и C++, игнорируя, что C++ за последние 30 лет сильно улучшил memory-safety по сравнению с C — STL containers, smart pointers и т. д. (а в C++26 появился ещё и hardening стандартной библиотеки, который убирает множество случаев UB из-за невалидных итераторов, выходов за границы массива, запрещённых операций над контейнерами и пр.). Есть инструменты статического анализа, которые встраиваются в IDE и CI/CD-пайплайны и которые помогают писать безопасный код и не требуют для этого сложных действий. Нет смысла оценивать безопасность C++ отдельно от этих инструментов.
Вообще, нет смысла говорить, что один язык memory-safe, а другой нет. Нужно взять конкретный инструментарий для конкретного проекта, включая весь CI/CD пайплайн, и определить его степень memory safety. И окажется, что между современным C++ и тем же C# разница не такая значительная, как все привыкли думать. Перекрывает ли эта разница те преимущества C++, которые я перечислил в статье — это дело вкуса. Лично для меня — не перекрывает даже близко.
Ваш первый комментарий был чересчур эмоциональным и игнорировал текст статьи, поэтому я не видел смысла полностью на него отвечать. Вся критика строилась на отсутствии стандартизованных инструментов и сложности подключения библиотек (это единственные конкретные недостатки, на которые вы указали), но вы эти проблемы упомянули как-то вскользь, без должного объяснения. Притом что я эти проблемы в статье описал подробно — если вкратце, там говорится, что у С++ более фрагментированная экосистема, чем у C#, но в ней есть и стандартизация ABI в рамах каждой платформы, и пакетные менеджеры, пусть и не с такими обширными репозиториями.
Что вы все как заклинание повторяете эту заезженную мысль? Каждый второй комментатор, кажется, уже написал, что их нельзя сравнивать. Ну а я вот взял и сравнил. Получается, что можно.
Мне любопытно — там есть ещё что-нибудь, что выглядит смешно? Сама постановка вопроса "что лучше - с++ или c#", которая в среде айтишников считается чуть ли не табуированной — не кажется слишком смелой? Обещание окончательно ответить на этот "вечный вопрос" не кажется гротескно самоуверенным? Большая синяя кнопка "Объективное и беспристрастное сравнение" вместо "Читать далее" не наводит на мысли? То что я весь 1-й раздел описывал боль, связанную с разработкой на плюсах, а потом вывернул это как преимущество C++, потому что "настоящие хардкорные программисты любят, когда язык их всячески сношает и заставляет преодолевать трудности" — вам не показалось, что это с самого начала задаёт весь тон статьи? Вы не увидели долю самоиронии в том, что C++-программистам меньше платят, а я подаю это как преимущество C++? А фраза "я должен быть строг, но справедлив — формально рефлексия в C++ есть, и через несколько лет, когда её доделают, она будет лучше, чем в C#" — показалась вам абсолютно серьёзной?
Сравнение производительности — это отдельный труд и отдельная статья, на которую у меня уже нет ни времени, ни сил. Тема этой статьи задана в первом абзаце — удобство самого языка и инструментов. Статья и так получилась большая, и я уже разобрал в ней достаточно много вопросов.
Что забавно, о чём вы говорите? У нас тут серьёзная статья.
Статистика StackOverflow для C++ показывает рост на 3% с 2023 по 2025
TIOBE Index показывает попеременно периоды уменьшения и роста, но если брать период с 2017, то метрика популярности C++ выросла на 3.5%.
На каких данных основано ваше утверждение, что "на C++ пишут всё меньше"?
Не знал. Спасибо!
И не говорите. Я даже два плюса из названия языка не стал засчитывать, а то было бы 10:1.
Вы возрождаете мою веру в людей. Поставил бы вам сердечко, если б мог.
Пожалуйста, пишите код единым блоком с указанием языка — на Хабре есть такая опция. С ней код получается компактным и с подсветкой синтаксиса.
Чтобы найти максимальный элемент, всё, что нужно — это либо оператор
<, либо оператор>. Это логично, и это то, чего ожидает пользователь. Делать функцию max, которая требует оператор-, да ещё иexplicit operator bool— это очень странный контракт, который вызовет недоумение у ревьюеров. Я даже не знаю, как прокомментировать этот код, чтобы меня не забанили. И почему в этих операторахb._valueне проверяется наnull?Использование
dynamicдопускает любые операции без compile-time проверок. Обе реализации функцииmaxиз статьи во время компиляции выполняют проверку, что у типа есть нужный оператор. Причём этот контракт явно декларируется в объявлении функцииmax, и при его нарушении вы получите ошибку компиляции, которая чётко и ясно скажет вам, что здесь не так. На каком основании вы заявляете, что этот код "такой же, как и у меня"?К чему там вообще
ToStringиoperator+? Что вы ими хотели сказать?И вы мне ещё объясняете, какой код "не пройдёт PR в нормальной команде". Да вы вообще имеете хоть какое-то отношение к IT?
Снова отметим пропуск неудобных вопросов:
К чему была аналогия с Феррари?
Зачем запрещать классы внутри функций?
Вы всерьёз собираетесь оспаривать, что возможности шаблонов на порядки шире, чем дженериков?
Как использовать max для типа, у которого определён только оператор
<, либо не реализован интерфейсIComparisonOperators?Зачем классам через интерфейсы сообщать о себе информацию, которая и так известна на этапе компиляции?
У меня весь первый раздел про то что C++ менее удобен в плане линковки, работы с зависимостями и в плане UB. С чем вы спорите?
Где в статье я демонстрирую непонимание, как работает линковка в шарпе, и где — непонимание, какие минусы несёт CMake? Процитируйте оба места.
У вас плохая кратковременная память. Про dll hell вы написали в другом треде, и я ответил уточняющим вопросом.
В моём примере этого нет, тем он и прекрасен. В вашем:
static void for_each_arg(Action<object> action, params object[] args) {...}используется массив object[], а массив в C# — это объект в куче.
Если в params передаются value types, то происходит их boxing при приведении к типу object:
for_each_arg(foo, 42);в куче создаётся object, содержащий 42. Это ещё одна аллокация памяти в дополнение к массиву args.
Рантайм каст нужен в функции делегата Action, чтобы выполнить логику над конкретным типом. В C++ в этом месте используется перегрузка функций, которая разрешается в compile time.
То есть я где-то в статье беру одну маленькую деталь, которую в худшем случае можно назвать неоднозначной, и из неё вывожу глобальное суждение о целой области? Или намеренно избегаю технических вопросов и перехожу на туманные формулировки и вкусовщину? Где именно я всё это делаю?
А где я говорю, что писать на шарпе — это ошибка? Я вообще-то сам на нём пишу.
Не угадали.
Просто купите более мощный комп, и проект, который собирался 4 часа, будет собираться всего за час. (если что, это сарказм, смешанный с самоиронией. Время компиляции в C++ действительно не радует)
В 7-м разделе статьи я подробно рассказал об "удобстве" контейнеров C# в сравнении с C++ и его итераторами.
Я за вас искренне радуюсь! Вы гораздо лучше меня умеете получать удовольствие от программирования на C#.
Да, и плюс вот это:
Но сказать-то вы этим что хотели?
Решено, и? Какое утверждение из статьи ваш намёк должен опровергнуть? Процитируйте.
Вы проигнорировали примерно половину моих вопросов. Спрошу ещё раз:
к чему была аналогия с Феррари, и какой тезис статьи она должна была опровергнуть?
зачем вы принялись рассказывать про бинарную несовместимость в C# и про непереносимость между ОС, притом что я сам рассказываю про эти проблемы буквально в том же предложении, которое вы цитируете?
Ответьте на них, пожалуйста, а то после таких возражений остаётся впечатление, что вы не читали статью, а просто скормили её LLM, и попросили написать комментарий.
То есть вы на полном серьёзе обвиняете эту статью в отсутствии объективности? Чем больше я вас читаю, тем больше убеждаюсь, что разговариваю с роботом, который не видит общую картину текста и не понимает его общий настрой. Я даже не буду вас разубеждать или что-то подсказывать — просто дам совет сначала читать статью, а потом писать комментарии.
Если операторы сравнения для класса возвращают другой тип, конвертируемый в bool, то вы не сможете использовать его с функцией max — это просто не скомпилируется. std::convertible_to — это пример гибкости концептов. С их помощью можно задать любые требования к параметрам шаблона. Возможности шаблонов в C++ на порядки шире, чем возможности C# дженериков. Вы всерьёз собираетесь это оспаривать?
Покажите, как в C# можно использовать функцию max для типа, у которого определён только оператор
<. Либо есть все 6 операторов, но не реализован интерфейсIComparisonOperators. Писать класс-обёртку, и в нём определять 6 операторов сравнения, 5 из которых вы никогда не будете использовать? Положа руку на сердце, вы считаете, что это пример хорошей архитектуры языка?В C++ вы выражаете требования в концепте, который сам достаёт всю информацию о классах, без помощи интерфейсов. Если для класса определён оператор <, то концепт просто это видит. Зачем классам через интерфейсы сообщать о себе информацию, которая и так известна на этапе компиляции? Это просто нелогично, и это ограничивает ваши возможности.
Из всех преимуществ шаблонов, о которых я рассказал, вы выдернули один
std::convertible_to<bool>, без которого операторы сравнения могут обойтись (ибо что ещё им возвращать кроме bool), и на основе этой мелкой детали сделали обобщённую оценку на весь раздел: "Вообще вся эта секция притянута за уши". Это приём из области демагогии.А что меняется для этого примера? Массив params[] перестаёт выделять память в куче? Для значимых типов перестаёт использоваться boxing? Или куда-то пропадает рантайм каст к нужному типу? Я вижу, вы решили проигнорировать технические возражения, надеясь, что никто не заметит, и сосредоточиться на вкусовщине: "то есть в плюсах это выглядит красиво? Абсолютно не читаемо". Это опять демагогия. Да и что значит нечитаемо? Во-первых, вполне читаемо, во-вторых используется обычно для классов с простым и понятным назначением, вроде function или tuple, код которых никому и не надо читать. В C# для Func написано 17 реализаций с разным числом параметров, а для ValueTuple — 8 реализаций — вот это реально нечитаемо, и к тому же ограничено по числу параметров.
А зачем запрещать? Программист сам может решить, что для его кода хорошо, а что плохо.
Наоборот, чтобы сделать код более читаемым и не засорять внешнее пространство имён каким-то мелким служебным классом, который имеет смысл только внутри этой функции.
Я не умею спорить в общем и целом, только по конкретным пунктам. У меня в статье этих конкретных пунктов полно — берите любой и приводите контраргументы.
Ну это перебор. Что не так с этими комментаторами?
Возражение было бы релевантным, если бы я сравнивал C++ и Excel. То, что их не нужно сравнивать — это клише. У них сильно пересекаются возможности и области применения. И их регулярно сравнивают. Выйдет какая-нибудь сложная статья по плюсам, обязательно в комментариях появится какой-нибудь г-н "Я 10 лет назад перешёл с C++ на C#, и до сих пор радуюсь своему решению и охреневаю от того, как у вас всё сложно и неудобно". А я вот, представьте, охреневаю от того как в сишарп всё сложно и неудобно.
Я сравниваю не области применения, а заложенные в них архитектурные решения, концепции и идиомы, а также удобство экосистемы и инструментов. Удобно ли пользоваться системами сборки и пакетными менеджерами, насколько удачным решением был Nullable контекст, в каком языке обобщённое программирование даёт больше возможностей, и т. д.
Если не можете найти тезисы в статье, то с чем вы спорите?
А в чём проблема?
+4 строчки на CMake.
Считайте как Вам угодно, но объективный и беспристрастный анализ показывает, что C++ выигрывает со счётом 8:1.
Но я же объясняю, в чём ошибка, просто за пределами спойлера )
Главное, что он помогает её найти.