Pull to refresh

Comments 334

В C# массив — ссылочный тип. Поэтому без проблем можно передавать в любую функцию. В C++ все контейнеры ведут себя как «размерные» типы и копируют все содержимое при передаче в качестве параметра. Нужно очень внимательно писать код для C++, чтобы не копировать лишний раз массивы. Зачастую придется прибегать к умным указателям, которые несут дополнительный оверхед.

У меня есть подозрение, что новичкам следует изучать эту проблематику, а у большинства опытных разработчиков проблем с передачей по ссылке или указателем нет.
Да-да, а еще у опытных разработчиков рабочих день из 30 часов и они цитируют Кнута наизусть в обратном порядке.

Тем не менее все люди и часто ошибаются (чаще чем кажется). А в C++ легко забыть написать передачу по ссылке и получите копию. Причем в некоторых случаях это даже логику программы не поменяет. А если помножить подобные проблемы на несколько типов уминых указателей, rvalue ссылки итп, то можно очень часто ошибаться.
Достаточно пару сотен раз обжечься и проблема забытой ссылки пропадает сама собой. Со мной в последний раз это случилось четыре года назад. Вернее, шесть лет назад, но два года эта ошибка не проявляла себя. Вектор передавался по значению, но почти всегда был из малого числа элементов и на производительности заметно не сказывалось. Лишь когда при определённом использовании размер увеличился до нескольких сотен элементов и производительность экспоненциально падать начинала (столь глупая ошибка была в рекурсивной функции), то косяк обнаружился. И сразу же был исправлен.
Столь громко осуждаемые и обсуждаемые ошибки с указателями, ссылками и прочим — по большей части удел студентов. Спустя несколько лет практики их уже на уровне инстинктов не допускаешь.А ещё помогает RAII и следование codestyle.
По поводу оверхеда умных указателей — в шарпе-то этот оверхед есть всегда и везде (unboxed не учитываем), а в Сишке только там, где пожелает программист.
Достаточно пару сотен раз обжечься и проблема забытой ссылки пропадает сама собой.

Без комментариев.

Эта пара сотен раз во сколько сотен тысяч долларов выльется?
Обычно пару сотен раз обжигаются быстро и в универе.
В универе не учат тому, что потом придется использовать в работе. Увы.
Ну вот конкретно примеру со ссылками меня как раз научили в универе. Я тогда слабовато знал С++, а нам устроили контрольную по алгоритмам в виде олимпиадного контеста: надо было писать код решающий задачи, отправлять его на сервер где он прогонялся на тестах, при этом были ограничения на время выполнения и на потребляемую память.

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

Так что универы тоже разные бывают.
Прекрасный пример. В C# такой проблемы вообще бы не случилось.
Зато в C# можно наколоться с boxing/unboxing, хотя масштаб разрушений обычно меньше.
UFO just landed and posted this here
В универе приходится отвлекаться на учёбу :(
UFO just landed and posted this here
Достаточно пару сотен раз обжечься и проблема забытой ссылки пропадает сама собой.

[Ирония]А ещё достаточно 10-20 лет пописать на ассемблере, и проблема сложности читаемости и написания кода на ассемблере отпадает сама собой. Главное следовать codestyle. А ещё код на ассемблере можно оптимизировать лучше, чем код на С++.
Чудаки, придумали тут несуществующую проблему. Терпенье и труд все перетрут! Долой автоматизацию труда программиста! Даёшь ассемблер! [/Ирония]
[Ирония]Чудная это обезьяна! Вместо того, чтобы по деревьям лазать, сбивает плоды палкой-копалкой. Ленивая какая-то. Сильные обезьяны так не делают! Достаточно пару сотен раз слазить на дерево, мышцы накачаются, и это не будет уже проблемой. Последний раз у меня были сложности с залезанием на дерево шесть лет назад. Терпенье и труд все перетрут! Долой автоматизацию труда обезьяны![/Ирония]
Без иронии.
Чудная обезьяна целую неделю страдала-голодала, но продолжала бросать палку-копалку в пробегающих мимо антилоп. Другие обезьяны над ней смеялись, ведь палка-копалка нужна, чтобы сбивать бананы, а не антилоп. А она продолжала бросать, пока не научилась попадать в цель и жрать питательное мясо. А другие обезьяны продолжали над ней смеяться и стали зваться вегетерианцами.

Вот вы реально проблемы на пустом месте придумываете. Студенты косячат и ругают указатели и прочее, но это совсем не проблема. Опытный программист просто физически не сможет написать код с вышеозвученными проблемами, потому что подсознание спать не даст, пока не исправишь эту ошибку. Про codestyle я написал не ради красивого словца, а по делу. Если чётко сказано, что входные параметры должны быть ко константной ссылке, а выходные по ссылке или указателю, то косяк просто не пройдёт code review. Не говоря о том, что в блокнотах кодят только обезьяны и любая современная IDE обнаруживает большинство ошибок (вы ведь читаете предупреждения компилятора?), и ещё больше ошибок отлавливаются специальными утилитами (блюющим единорогом) и профайлером.

Но уровень вхождения в C# несколько ниже, с этим соглашусь. Можно говнокодить не отстреливая ноги из верёвки.
Необходимость работать с памятью вручную нагружает программиста дополнительной работой. Нужно написать деструктор, конструктор копирования (без него деструктор и копирование будут работать некорректно), следить что delete вызывается там где нужно, следить передаются у вас аргументы в функцию по ссылке или через копирование в стек и т.п.
Вы более шести лет этим занимались, и поэтому вам этот рутинный труд кажется чем-то само-собой разумеющимся. Ну и эффективность вашего труда вас тоже не сильно беспокоит.
То, что нужно вручную делать монотонный труд, который можно легко автоматизировать — это проблема. Иное дело, что иногда в силу обстоятельств нужно закрыть глаза на эту проблему, потому что по-другому сделать не получится. Но от этого неудобство не перестаёт быть неудобством.
То, что вы в течении шести лет писали конструкторы копирования, не даёт вам права называть студентами и второсортными программистами тех, кто не хочет заниматься их написанием. Ну если не занимается человек микроконтроллерами, то зачем ему выполнять этот рутинный труд? Ради выигрыша в 10%-20% в скорости из-за того, что в С++ нет всевозможных проверок на выход за границы массива (не забываем про JIT-компилятор)? Нет, спасибо, я предпочитаю наличие таких проверок на уровне языка.
Нет почти по всем озвученным тезисам.
Начну с конца.
Я не называл студентами и второстепенными тех, кто не хочет писать конструкторы, я называл студентами и второстепенными программистами тех, кто не может поставить символ & и делает из этого трагедию. Впрочем, я не называл никого второстепенными и студентами называл не в обидном смысле слова, а в смысле временного отсутствия опыта.
Конструкторы и деструкторы нужны не только и не столько для освобождения памяти. Скажу больше, сейчас у меня в проекте около полутора тысяч файлов, при этом new и delete используются буквально в десятке из них. Вызывать вручную delete? Ну написал его один раз в деструкторе — руки не отвалятся.
Если не выделять память через malloc/new, а использовать контейнеры, то писать конструкторы копирования(а ещё и присваивания!) не нужно. Если следовать RAII, то и деструкторы не всегда нужны, по крайней мере delete в них писать точно не придётся.
Выход за границы массива проверяются в дебаге и в релизном коде уже в принципе не должно быть выхода за границы (я метатель). При желании, можно проверять выход за границы массива и в релизном коде (at вместо []). Это С++, тут можно практически всё, было бы желание.
В современном программировании под «ручным управлением памяти» подразумевается, что программист в любой момент времени знает, существует ли объект или нет и знает, когда именно этот объект будет уничтожен. Может сам выбрать для этого момент, чтобы был наименьший удар по производительности. Может вообще не разрушать объект. А может положиться на RAII и вообще быть не в курсе, что такое ручное управление.
Скажу больше, сейчас у меня в проекте около полутора тысяч файлов, при этом new и delete используются буквально в десятке из них.
Понятно, вы не испытываете проблем с управлением памятью в куче, потому что ваш codestyle подразумевает отказ от выделения памяти в куче. Ну так, с этого и следовало начинать. А если человек не хочет ни в чём себя ограничивать, и не хочет заниматься лишним рутинным трудом, предпочитая автоматизацию? Ну и да, в этой рутине тоже можно допустить ошибку.

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

я называл студентами и второстепенными программистами тех, кто не может поставить символ & и делает из этого трагедию
На эту тему я уже высказался. Можно лазать по деревьям и гордиться своим умением не наступать на тонкие ветки и не будить спящих на дереве змей, а можно сбить фрукт палкой-копалкой. Вы же почему то высказываетесь против палки-копалки. Ваша позиция: «Будь мужиком — лезь на дерево. Не умеешь лазать по дереву — не мужик». Тут абсолютно неважно, умеет ли человек, пользующийся палкой-копалкой, не будить спящих змей на дереве. Важно, что вы выступаете против прогресса.
Не спорю, в редких ситуациях умение лазать по дереву может оказаться очень кстати. Но это не повод каждый раз лезть на дерево и заниматься рутинным трудом, когда этого можно и не делать. Просто признайте, что вам лень изучать принцип работы палки-копалки и занимайтесь вашим рутинным трудом дальше на здоровье. Зачем тормозить развитие других соплеменников? Если человек не хочет заниматься рутинным трудом, а хочет уделять больше времени более творческим задачам, и современные технологии (в том числе быстродействие современных компов) ему это позволяют, то почему бы и нет???
Добавлю, что в редких случаях и знание машинных кодов нужно. Но это не оправдывает позицию: «Будь мужиком — пиши на машинных кодах. Тот, кто не знает машинных кодов на уровне подсознания — не мужик.»
Я себя ни в чём не ограничиваю! Благодаря stl и прочим контейнерам отпадает необходимость в ручном выделении/удалении памяти для коллекций. Штучные объекты создаются менеджерами объектов(как раз те редкие файлы с new/delete), но это сделано не ради отказа от new, а из-за фабрик полиморфных объектов. Кстати, есть множественное и пирамидальное наследование, но проблем с ним тоже нет. Это я вспомнил ещё один популярный камень в огороде С++.
То есть вы не делаете дополнительных действий, которых можно было бы избежать, если бы использовался сборщик мусора и ваши классы всегда передавались в функцию по ссылке?
Дестркуторов не пишете? Код дополнительно взглядом не окидываете в поисках ошибок работы с памятью? Специальные анализаторы кода периодически не запускаете? И в куче при этом объекты создаёте? Вот что-то не верится.
Деструкторы нужны НЕ для того, чтобы вызвать в них delete. Например, сокеты я тоже в деструкторах закрываю. И с файлов блокировку снимаю. И с тех же мьютексов. Я не знаю, есть ли в C# деструкторы, если нет, то пичалька, придётся каждый раз в блок finally писать код, который можно один раз в деструктор написать.
Мне не нужно ВСЕГДА передавать классы по ссылке, потому что в некоторых случаях эффективнее по значению. Что? В шарпике тоже можно по значению передавать, но только структуры? А вот в плюсиках можно передавать так, как хочешь. А ещё можно передавать по значению, но при этом копирования объекта не будет, потому что изначально будет использоваться тот объект, который потом вернётся из функции. Да, С++ и так может, потому и компилируется код долго, что он много чего может.
Я окидываю код взглядом сотни, а то и тысячи раз. Не ради ошибок работы с памятью — этот класс ошибок у меня практически устранён на уровне архитектуры приложений. Я в принципе стараюсь не писать такой код, в котором могут быть ошибки работы с памятью. То же касается и ошибок переполнения буфера.
Анализаторы кода запускаю раз-два в месяц (не считая того анализа, на который способен компилятор при каждой компиляции). Логические ошибки обнаруживаются периодически. Неправильная инициализация обнаруживается. Дублирующиеся и не эффективные сравнения обнаруживаются. С памятью пока ничего связанного не обнаруживалось.
У Макконелла по этому поводу очень хорошо было написано: Выделил память, сразу же напиши код её освобождения. Всё проблема решена.
JFYI: в C# есть и деструкторы, и детерминированное освобождение ресурсов.
Как там может быть детерминированное освобождение ресурсов, если там сборщик мусора?
Про деструкторы — спасибо. Теперь вдвойне забавно выглядят крики о нудном создании деструкторов в плюсах.
Как там может быть детерминированное освобождение ресурсов, если там сборщик мусора?
А по вашему закрытие файлов и соединений (connection) можно сборщику мусора доверить? Такие ресурсы нужно как можно раньше освобождать.

Теперь вдвойне забавно выглядят крики о нудном создании деструкторов в плюсах.
Финализаторы в С# не занимаются непосредственным освобождением памяти в куче. Да и используют их довольно редко.
> А по вашему закрытие файлов и соединений (connection) можно сборщику мусора доверить?

Не вижу связи между закрытием соединения и освобождением памяти. И вообще, закрытие сокетов или файлов я уже использовал в качеств аргумента для создания деструктора в С++ — не засчитано. Своё придумывайте.)
Как там может быть детерминированное освобождение ресурсов, если там сборщик мусора?

Да легко, типичное кооперативное поведение. Сначала объявим класс, заинтересованный в детерминированном освобождении:

class DeterministicResource: IDisposable
{
  void IDisposable.Dispose()
  {
     //освобождаем ресурсы
  }
}


Теперь используем объект такого класса (при условии, что мы хотим детерминированного поведения):

using(var r = new DeterministicResource())
{
  //делаем что нам надо с ресурсом
}


Прелесть в том, что как только мы покинули using (причем покинули любым способом — просто вышли за границу, сделали return, бросили exception), компилятор C# гарантирует вызов метода Dispose. Вторая прелесть в том, что если мы при этом используем только управляемые ресурсы, то если вызова Dispose не произойдет (например, пользователю класса не важное детерминированное поведение), ресурсы все равно будут собраны, просто позже.

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

Я просто подозреваю, что семантика деструкторов в C# и C++ отличается. В C# дескриптор — точнее, финализатор — нужен исключительно редко, и обычно это случается при взаимодействии с неуправляемыми ресурсами. Я за свою жизнь их написал явно меньше десятка.
Например, деструктор может делать то же самое, что Dispose, без необходимости наследоваться от IDisposable. Я там оговорился и вместо «освобождение памяти» написал «освобождение ресурсов». В контексте сборки мусора и управления памятью речь шла о памяти, а не о ресурсах вообще. GC сработает так, как ему приспичет и тогда, когда ему приспичет. В С++ момент освобождения памяти детерменирован, если не используется сборщик мусора.
Ну, если вам очень надо детерминированное освобождение памяти, то есть GC.Collect(). Другое дело, что не надо этого в .net делать, не идиоматично это.

Я говорил именно о ресурсах.
UFO just landed and posted this here
В данном случае ответ однозначно нет (передан по ссылке, косяк в примере). А вот умрёт ли он после возврата из функции сказать сложнее, для этого нужно глянуть на счётчик ссылок в указателе.
О детерминированности. Умный указатель (объект, на который он ссылается, если точнее) будет разрушен в тот момент, когда счётчик ссылок обнулится. Детерменированно? Абсолютно. Локальная переменная будет разрушена при выходе из области видимости(RAII) или при вызове delete. Тоже абсолютно детерменированно. При использовании сборщика мусора можно определённо сказать лишь то, что пока объектом пользуются — он точно существует. И может существовать какое-то время после того, как им уже никто не пользуется.
UFO just landed and posted this here
Выделил память, сразу же напиши код её освобождения.
Если у вас объект создаётся в куче через фабрику, то для соблюдения этого принципа у вас используются менеджеры объектов, как я понял с ваших слов. Эти менеджеры объектов надо как-то оповещать, чтобы они поняли, что пора сделать delete. Создание менеджера и его оповещение — это дополнительные приседания. Опять таки создание объектов в куче у вас наверное не всегда через фабрику делается. Если всегда, то пложение фабрик где надо и не надо — опять таки дополнительные приседания, ну или в чём то вы себя всё же ограничиваете в плане использования кучи.

Деструкторы нужны НЕ для того, чтобы вызвать в них delete.
А если в конструкторе был выделен массив в куче, то где прикажете его освобождать? Отдельную функцию завести? И в чём выгода, почему не в деструкторе?

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

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

Да, С++ и так может, потому и компилируется код долго, что он много чего может.
Вы уверены, что дело в богатстве возможностей языка, а не в компиляторе? Кстати, C# тоже умеет много чего, чего не умеет С++: рефлексия, динамическая кодогенерация, динамик прокси (на основе кодогенерации), мок-объекты (на основе динамик-прокси)
> А если в конструкторе был выделен массив в куче
vector и никаких куч

> Передача по значению происходит путём копирования полей объекта в стек.
С++11 и конструктор перемещения. Если компилятор сочтёт эффективным, то вместо копирования будет редактирование того объекта, который будет возвращён из функции, а не объекта, который будет затем скопирован.

> что столь опытный программист, коим вы себя позиционируете
Я ни слова не говорил о своём абсолютном опыте, а лишь относительно автора статьи. Например, С++14 я вообще не знаю. C# я вообще почти не знаю, поэтому без деструктора варианта кроме finally не вижу (мне уже сказали, что деструктор есть, всё ОК).

> C# тоже умеет много чего, чего не умеет С++
С++ тоже это всё умеет. Только это придётся самому запрограммировать…
vector и никаких куч

У вектора есть деструктор. И вектор хранит свои элементы в куче.

придётся каждый раз в блок finally писать код, который можно один раз в деструктор написать
Стандартное средство борьбы с дублированием кода — вынесение дублирующегося фрагмента в отдельную сущность. От языка практически не зависит.

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

Это если по-умолчанию, передаём что-то типа вот такого аллокатора — и всё на стеке
> У вектора есть деструктор. И вектор хранит свои элементы в куче.
В управляемых языках тоже есть и куча и стек и регистры процессора, но речь же о ручном освобождении памяти.

> вынесение дублирующегося фрагмента в отдельную сущность
И ручное прописывание этой функции в finally, что то же самое дублирование, только в меньшем масштабе. Мне уже ответили, что в шарпе есть деструкторы, так что этот пункт с повестки снимается.

> И как это вы интересно будете делать рефлексию?
> научите рефлексии без препроцессора (это из коммента ниже, но я только раз в 5 минут писать могу, так что тут отвечу)
Почему в Шарпе можно дописывать аттрибуты и свойства и всякое разное, чтобы включить поддержку какой-нибудь рефлексии, а плюсы должны быть прям по учебнику и даже без препроцессинга? На С/С++ можно запрограммировать практически всё что угодно, вопрос только в велосипедах и костылях. Раз в С++ до сих пор нет рефлексии, значит, она не настолько востребована в высокопроизводительных приложениях. Либо её нельзя эффективно реализовать в принципе. Я не пользовался рефлексией в других языках, так что не знаю обо всех сферах её применения.
С другой стороны, чем словарь из строк и функторов не рефлексия? Типа map<string,functor)? Повторюсь, я не знаю, что такое рефлексия и описание из википедии похоже именно на добавление/подмену методов класса.
Почему в Шарпе можно дописывать аттрибуты и свойства и всякое разное, чтобы включить поддержку какой-нибудь рефлексии,

Подозреваю, что вам все-таки лучше сначала узнать, что такое reflection, и как он устроен в .net, прежде, чем спорить на эту тему. Ничего «дописывать» не надо, рефлексия работает всегда и доступна из коробки.

Раз в С++ до сих пор нет рефлексии, значит, она не настолько востребована в высокопроизводительных приложениях.

Тут возникает разумный вопрос: а «высокопроизводительные приложения» — это единственная область применения С++?

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

Если вкратце, то reflection (по крайней мере, в .net) — это способность в рантайме получать метаданные кода (как выполняемого, так и нет), и потом выполнять код на основании этих метаданных. Типичный сценарий — имея на входе класс (не объект), получить список всех свойств, определенных в этом классе, затем сопоставить их с входными данными (скажем, xml-файлом), и создать объект этого класса, где свойства будут заполнены входными данными.
Да, без подключения интерпретатора или кодогенерации вряд ли получится в плюсах рефлексию использовать. Но если только данные(свойства), без поведения, то хоть на Сишке можно сделать. Разумеется, будет не так красиво, как на шарпе.
UFO just landed and posted this here
я правильно понимаю, вы весь этот код написали ради SetAvatar/GetAvatar?
а вы не думали что даже прямое использование, довольно примитивного SQLite API в этих функциях займет меньшее число строк кода, чем у вас?

P.S. отсутствие рефлексии в С++ конечно расстраивает…
UFO just landed and posted this here
кхм, как вы умудряетесь так много и постоянно комитить )?
Напишите свой Leechcraft — поймёте =)
UFO just landed and posted this here
.У меня есть очаровательный пример. Не могу сказать, чтобы я был крутым спецом в C++, но «пару сотен раз обжечься» со мной случалось. Припомню лишь один такой случай (один из последних).

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

В один не очень прекрасный момент я обнаружил, что программа моя падает при завершении. Пока работает — всё окей. А на выходе «на посошок» — SEGFAULT. Думаю, все с таким сталкивались.

Долго я ломал голову, в чем дело. На что только не думал. Все деструкторы по 20 раз проверил, брейкпоинтов понаставил… Всё тщетно. Решение обнаружилось при внимательном перечитывании кода, к которому я пришел от отчаяния. Один объект получал в конструкторе ссылку на другой и тут же ее сохранял. То есть, конструкция такого вида:
public: A(B& b): m_b(b) {...}

Оба объекта были крупными модулями логики программы. Ошибка состояла в том, что я прозевал и не написал амперсанд.

И, не говоря мне ни слова, компилятор честно скопировал объект b. Тот был для копирования не предназначен и при деструкции я получил ошибку двукратного освобождения памяти (которая под MINGW, почему-то, обратилась SEGFAULT-ом).

Сейчас я, конечно, понимаю, что в классе B можно было запретить копирование, создав неимплементированный оператор присвоения и копирующий конструктор (ибо он действительно был не предназначен для копирования). И, конечно, имей я чуть больше опыта, я бы, в первую очередь посмотрел именно в сторону ссылок, а не деструкторов.

Всё это справедливо. Я своей глупости не отрицаю.

Но есть и другая правда. А именно: язык, в котором один забытый символ в типично используемой конструкции приводит к появлению трудновылавливаемой ошибки времени исполнения с молчаливого одобрения компилятора — плохой язык. Он спроектирован из расчета на непогрешимость разработчика. А разработчик — человек, ему свойственно ошибаться и платить головой (или целым днем работы) за мелкую опечатку — совсем не комильфо.

Я навскидку предложу 2 варианта решения проблемы, которые, почему-то, не пришли на ум господину Страуструпу (или он, почему-то, не счел их приемлимыми).

1. Запретить «неявный» копирующий конструктор для объектов и то же самое — с оператором присвоения. Хотя бы заставить разработчика явно написать «разрешаю копирование» в декларации класса, чтобы исключить «недоразумение по умолчанию». Я бы не поленился пару слов написать — это быстрее, чем полдня дебажить.
2. (Прекрасное решение, реализованное в языке C#) Поделить все объекты строго на две категории — те, которые всегда передаются только по ссылке и те, которые передаются исключительно по значению. В 99% случаев никому не нужно один и тот же объект передавать и так, и так. Для остального 1% нетрудно создать метод «clone» или что-то в этом духе.

И таких примеров много. C++ плох тем, что он, помогая разработчику писать код, не мешает ему делать серьезные ошибки. Он не защищает от ситуации, когда ошибка в одном модуле приводит к падению в совсем другом. Иногда проще переписать программу с нуля, чем поймать случайный memory corruption crash…
По сравнению с C, в ногу таки выстрелить сложнее. Но если вам это удастся, то попрощайтесь со всей ногой.

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

Я еще раз повторю — я свой косяк не отрицаю. Но вот в остальном я с вашей логикой совершенно несогласен:
То, что не предполагает копирования, всегда должно иметь соответствующую защиту

В языке C++ — именно так. В нормальном ЯП — совершенно неверное утверждение. Я не был в армии, но полагаю, что когда (если) личному составу выдается заранее заряженное оружие, предохранитель должен быть выставлен по умолчанию. Спуск можно нажать случайно. Можно просто уронить оружие. Мало ли, какие случайности бывают…
В языке Паскаль, например, по умолчанию был выставлен range checking. Да, его можно отключить, но если ты это сделал, то либо ты знаешь, что творишь, либо — «сам себе злобный Буратино». А когда у меня вся панель управления забита «красными кнопками» без защиты, то это — не боевая машина для профессионалов. Это — минное поле.

А теперь — без метафор. Любая система, предназначенная для использования людьми, должна быть спроектирована так, чтобы повышение опасностей и рисков (а не понижение их) достигалось дополнительными усилиями. В областях инженерии, где риск носит фатальный характер, это давно усвоили. Например, на заводах в цехах штамповки и резки станок имеет не одну спусковую кнопку, а две. И расположены они в разных его концах, а нажимать их надо ладонями, одновременно. Как считаете, там много работает идиотов, которые не знают, что руки под нож совать не следует? И тем не менее, одного «понимания» этой банальности работниками инженерам показалось недостаточно — они специально сделали так, чтобы руки были заняты в момент удара.

В Java есть миллион способов убить программу неопределяемой ошибкой. Но для этого надо как минимум задействовать рефлексию. А лучше — JNI. Еще лучше — динамическую кодогенерацию на JVM. И объем кода, на котором это удастся сделать — тысяча классов. На меньшем вы с легкостью найдете ошибку.

А если мне надо высокую производительность, я напишу кусок функционального кода на C и сделаю JNI-интерфейс. Это — тоже риск, но там проблем меньше. Да и редко это бывает необходимо, откровенно говоря.

Я честно старался полюбить C++. Изучал его несколько лет (параллельно с C# и Java). Писал что-то на нем. Но всякий раз я втыкался в совершенно непредсказуемые результаты совершенно, на первый взгляд, безобидных действий.
Я вас поздравляю, вы подстрелили инструктора на стрельбище и угодили под военный трибунал. Заранее заряженное оружие не дают, вы его сами заряжаете. Так что оправдания вроде «а чего он сам на предохранитель не поставился?» на трибунале не пройдут.
Не все люди пригодны к военной службе. Из моих знакомых, занимающихся наукой, программированием и прочими интеллектуальными дисциплинами в армии не служил никто, а военные сборы посещали единицы.

Я предпочитаю пользоваться инструментами, которые помогают мне в работе, а не дергают за нервы. Я могу писать на C++. Просто он мне неприятен. И аргументов хватит на целую статью, просто писать ее смысла нет. Одни люди со мной и так согласны (многие из них знают этот язык лучше меня), а другие (в частности, вы), к подобным аргументам не прислушиваетесь. Я высказал лишь самое вопиющее.
Тогда приведите пример инструмента, который так же гибок, быстр, дает работать напрямую с памятью, создает код почти для любой платформы, но не имеет минусов C++.
Последние два года я разрабатываю проекты, включающие в себя 2 слоя. Нижний уровень пишется платформонезависимым способом на языке Си. Это обычно высокоскоростной слой, который занимается взаимодействием с графикой или чем-то подобным. Дальше идет JNI-интерфейс. Верхний слой пишется на Java. Там находится вся логика, там если и приходится думать об управлении ресурсами, то только в рамках имплементации интерфейса Disposable.

Взаимодействие с ОС осуществляется через JRE, поэтому проект получается кроссплатформенный.

При этом критерий использования Си таков: на нем надо писать либо то, что даст этим существенный выигрыш производительности, либо то, что по каким-то причинам не может быть написано на Java (например, OpenGL-вызовы).

Java непригодна для оперирования большими массивами данных — она слишком много времени тратит на выделение/освобождение памяти. Но если не тащить в нее многомегабайтные буфера (а в этом обычно нет необходимости), то писать на ней управляющий слой, для которого и нужно ООП — одно удовольствие.

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

Так что они превосходно дополняют друг друга.

Для разработки я применяю IDE Eclipse, в которой можно одновременно исполнять и отлаживать и C, и Java.

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

Писать контроллеры на C++ гораздо труднее. И UI тоже, даже несмотря на такие мощные инструменты, как Qt.
Ну и D заодно. Вопрос другому человеку задавался, но я подозреваю, что оба эти языка, как и C++, этому человеку нравиться не будут.
D — отличный язык. Если бы я сочинял свой, он бы был очень на него похож. Но, увы, инфраструктуры в нем… нет. От слова «совсем». Если бы существовала надежная, нормально доделанная среда разработки, более-менее вменяемая стандартная библиотека, желательно, стандартизованная (или хотя бы популярная) и если бы хоть пара крупных компаний в него вложились, написав на нем что-то крупное… Искренне желаю этому языку всего вышеперечисленного.

Rust не знаю, но в лучшем случае все вышеперечисленные комментарии — про него тоже.
По D у вас устаревшие данные.
Перепроверил.

github.com/DDT-IDE/DDT/blob/latest/documentation/Features.md#features

Выглядит уже более-менее симпатично. Но по-прежнему сыро. Можно попробовать написать что-то небольшое на нем. Авось лет через 10 он появится в списке полезных технологий в собеседованиях на технические вакансии.
Так просветите. Вы же в нем разбираетесь.
Да заглядывал. Какой смысл мне от того, что Facebook где-то задействовал D, если я даже не знаю, где?

Остальные названия я не знаю. И, к тому же, сам факт наличия такого списка на сайте языка означает примерно следующее: «Посмотрите, какие мы взрослые, нас даже ФЕЙСБУК заметил!»

То есть попробуйте такой список для того же пресловутого C++ составить. Или для Java.

Понимаете? Для этих языков проще перечислить, что написано НЕ на них.

Я, вместо этого, посмотрел, с чем придется столкнуться разработчику, который захочет писать на D. И вижу я только минимальную поддержку Intellisense в IDE (что, конечно, хорошо), отсутствие, например, рефакторинга кода (что означает, что авторы плагина крупные проекты не пишут), только-только более-менее отлаженную стандартную библиотеку и гордый список «Нас Заметили».
И, не говоря мне ни слова, компилятор честно скопировал объект b.

Это странно. Что за версия компилятора, какие флаги сборки? Вот пример, у меня он не собирается (gcc 4.9.3):

ideone.com/M535ZN (clang 3.7)
ideone.com/42XEHl (gcc 4.3.2)

Или не было и звёздочки перед m_b? Это уже двойная забывчивость какая-то. Но и такая лечится одним запуском valgrind/cppcheck:
Cppcheck
user@host [tmp]$ cppcheck --enable=all copy.cxx
Checking copy.cxx...
[copy.cxx:1]: (style) 'class B' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.


Valgrind
user@host [tmp]$ valgrind ./a.out
==25907== Memcheck, a memory error detector
==25907== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25907== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==25907== Command: ./a.out
==25907==
==25907== Invalid free() / delete / delete[] / realloc()
==25907==    at 0x4C2A8E0: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25907==    by 0x4006C4: B::~B() (copy.cxx:7)
==25907==    by 0x400674: main (copy.cxx:22)
==25907==  Address 0x5a12c80 is 0 bytes inside a block of size 40 free'd
==25907==    at 0x4C2A8E0: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25907==    by 0x4006C4: B::~B() (copy.cxx:7)
==25907==    by 0x4006FB: A::~A() (copy.cxx:13)
==25907==    by 0x400668: main (copy.cxx:22)


Не пользуетесь must-have инструментами — тут уж кто виноват.

1. Запретить «неявный» копирующий конструктор для объектов и то же самое — с оператором присвоения.

Если в классе нет указателей — незачем писать копирующие конструкторы и операторы присвоения, компилятор генерирует их адекватными по умолчанию. И это удобно. Есть указатели — нужно либо указать, что копировать объект нельзя, либо реализовать копирование самому. Это можно прочесть в любой книге по C++ для начинающих.

Реализация запрета оставлена на плечах разработчика и делается одной строкой.
Скрытый текст
// pre-C++11
class B {
public:
    B() {
        a = new int[10];
    }
    ~B() {
        delete[] a;
    }
private:
    B(const B&) {}
    int *a;
};

// C++11
class B {
public:
    B() {
        a = new int[10];
    }
    ~B() {
        delete[] a;
    }
    B(const B&)=delete;
private:
    int *a;
};


Хотя бы заставить разработчика явно написать «разрешаю копирование» в декларации класса, чтобы исключить «недоразумение по умолчанию». Я бы не поленился пару слов написать — это быстрее, чем полдня дебажить.
Одно слово.
Скрытый текст
// C++11
class B {
public:
    B() {
        a = new int[10];
    }
    ~B() {
        delete[] a;
    }
    B(const B&)=default;
private:
    int *a;
};


Работает только начиная с С++11, это да.
Было это пару лет назад. Звездочки перед m_b не было, потому что m_b было ссылкой. Вот только я, честно говоря, позабыл, где именно я амперсанд потерял — в конструкторе, или в декларации ссылки. Скорее, конечно, второе… Детали уже не помню. Никакого C++11 — только старый стандарт.

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


Я как раз этим и руководствовался — классы-модули связывал по ссылкам, а не по указателям.

Как реализовать запрет копирования, я знаю. Тогда, возможно, еще не знал, но это не важно.

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

Возьмите школьника и крутого профессионала. Дайте каждому из них Java и C++. И адекватную каждому задачу. И вы увидите, что на Java каждый напишет сообразный своему уровню программу. Код, написанный школьником на Java, будет ужасен, неэффективен и переполнен антипаттернами. Но он будет работать. Потому что все ошибки, которые создаст «юное дарование», оно же при должном усердии сможет починить. У него всё будет под контролем.

А вот на C++ он не напишет ничего. Потому что любая программа сложнее «скажите А, скажите Б, вот вам А+Б» у него будет крэшиться и требовать для исправления проблемы более глубокого уровня понимания, чем тот, которым он владеет на данном этапе. Он впоследствии, возможно, поймет, что сделал не так. Но будет поздно.

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

Некоторые считают «вот не напишет школьник ничего на C++ — и хорошо нечего быдлокодерам в святыни лезть грязными руками». Но я полагаю, что это — всего лишь результат запредельной, избыточной универсальности и свободы, которую дает C++ и плохого проектирования.
UFO just landed and posted this here
Если бы у дрели был функциональный режим, не подразумевающий необходимости ее включать, то человек, не умеющий этого делать, должен был бы быть способен эту возможность использовать.

Я сам лет до 15-и не задумывался, для чего нужны эти странные «рога» на противоположной стороне молотка. При этом я с успехом забивал гвозди. Инструмент щедро предоставлял мне тот набор функциональности, который я был способен использовать. Вы вряд ли обрадывались бы, если бы перед использованием дрели вам приходилось сдавать экзамен не только по правилам техники безопасности (тут я ничего против не имею), но и, скажем, по ее инженерной конструкции.

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

(Утрирую для понимания) Представьте себе язык программирования, который требует знания высшей математики для того, чтобы написать на нем тетрис. Как считаете, хороший он? Удобный? Я сомневаюсь.
UFO just landed and posted this here
зато там будут объекты не удаляться-освобождаться, потому что он забыл их из коллекции удалять, когда они перестают быть нужны. Это сильно лучше, что ли?


Лучше. Потому что этот школьник, написав работающую программу, одну, другую, третью, постепенно будет учиться, развиваться. И в итоге вырастет в специалиста, который создает классные продукты. Все мы когда-то «забывали объекты из коллекций удалять».

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

Хорошо ли это? Я считаю, что когда люди развиваются, а не бросают всякие попытки на старте — это, несомненно, хорошо.

Что до Хаскелля, то вы слабовато взяли. Давайте прямо сразу Пролог возьмем. Вот где надо много знать, чтобы простейшую задачу решить. Только почему-то им вообще мало пользуются. И студенты, которым им мозг компостируют, вместо программирования идут компьютерные сети прокладывать. А потом — в менеджеры…

C++, в отличие от Хаскелля, позиционируется, как инструмент, пригодный для решения простых задач — UI там писать, игры… И, что характерно, именно это на нем обычно и пишут. Так уж сложилось. Но вы вряд ли найдете вменяемого человека, который станет писать графический редактор или игру на Хаскелле. Разве что из соображений обучения.
UFO just landed and posted this here
Это какой-то школьник с завышенным ЧСВ и уверенностью в собственной непогрешимости


Нет. Просто человек слаб. И всегда обвиняет в своей слабости других. А если он еще и неопытен… Он вам ничего не скажет. Просто пойдет писать стихи.

Компостирование конкретными языками — это уровень ПТУ, а не высшего учебного заведения.


Город Нижний Новгород. Несколько факультетов в ННГУ и НГТУ. Такие вот у нас в стране два именитых «ПТУ».

Оба этих языка вроде как описываются как языки общего назначения, значит, на них обоих можно писать что игры, что UI.


Можно. Покажите мне крупную коммерческую игру на Хаскелле и я с вами соглашусь, что он для этого удобен. Пишут, что-то больше на C# (Unity), на Java и на Python. А на C++ движки делают.

Я думаю, что функциональная парадигма в архитектурном плане менее мощна, чем ООП. Она не только сложнее для понимания, но и более хлопотна. И, да, список впечатляет.

Никого я никуда не записываю. Просто считаю, что те, кому всерьез надо игры делать, берут что-то более мейнстримовое. По куче причин.
UFO just landed and posted this here
У большинства от того, что все работает, будет меньше мотивации повышать качество своего кода. Ведь работает же!
Мотивация повышать качество кода — резльтат любви к делу и наличия эстетического чувства. Ни то, ни другое не разовьется, если у вас ничего не получается путного с самого начала.

У меня работало. И в детстве на Паскале, и в более старшем возрасте на Delphi, затем немного на C#, потом на Java (в том числе, под Android). И иногда на C и C++ работало, но меньше и хуже. Но если C — неизбежное зло для того, кто хочет писать быстрый код под платформу, то в чем неизбежность C++, я так и не понял. Даже сообщения об ошибках при наличии в коде хоть пары шаблонов читать — кошмар сущий.
UFO just landed and posted this here
пригодный для решения простых задач — UI там писать, игры…

Эм… с каких пор написание UI и игр перешло в раздел простых задачь?
С тех же самых пор как и
В Си нет ООП

В Си ООП нет. Это я вам могу сказать после того, как участвовал в течение 2х лет в разработке под платформу BREW (https://en.wikipedia.org/wiki/Brew), которая написана на Си и в которой ООП было на всех уровнях.

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

Теоретически можно поддерживать любую парадигму на любом языке. Можно писать ООП на Си, можно писать ASM-way на Java. Просто это запредельно неудобно.
Вы написали чепуху. Ни в одном языке нет ООП. ООП реализуется при помощи языка. Причем он может и не быть объектно-ориентированным. А в С есть структуры, в которые можно укладывать указатели на функции. Quake 2 по сути был написан с использованием ООП но на C.
,
Вы под ООП понимаете только наличие виртуальных функций?
А вы сделайте ревью кода Q2 и сами решите. Это был всего навсего пример того, что для ООП не всегда нужен OOЯП.
Я написал не чепуху. Просто у нас с вами разные понятия.

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

Си не предназначен для ООП. В нем нет ни понятия класса, ни понятия инкапсуляции, ни полиморфизма. В рамках Си можно создать «игрушечный» полиморфизм, организованный вами же как набор указателей на функции. Можно написать #define CLASS struct. Можно много чего сделать. Но от этого сам язык не станет удобнее при использовании этих возможностей.

Компилятор не обругает вас за попытку вызова private-метода, система контроля типов не подскажет вам, что вы присваиваете яблоки к крокодилам. Всё то, что является основными преимуществами современного ООП, совершенно не будет работать.

Вы всё будете делать «руками». За всё будете отвечать сами. А когда програма «обрушится», вы получите совершенно не читаемый стек, состоящий из функций с большим количеством подчеркиваний в именах, которые вы не вызывали (потому что они развернулись из препроцессорных макросов) и будете всякий раз гадать, в какой вообще строке у вас случился креш.

Вот именно это всё я и подразумевал под фразой «В Си ООП нет».
Попытка выкрутиться провалена. Вы расскажите это разработчикам Linux kernel и Asterisk.
Дорогой друг! Во-первых, не грубите. Я не выкручиваюсь, а дискутирую. Высказываю те аргументы, в которые верю.

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

А в третьих, тот факт, что во многих проектах, в которых требуются запредельные условия (например, сочетание низкого уровня и сложной архитектуры), используются инструменты, лишенные удобства для разработчика, не отрицает того, что они неудобны. Кстати, в ядро Линукса C++ не пускают. Что тоже намекает…

Еще раз: когда на использование языка обрекает нужда и выбора нет, используют то, что есть. Вот, на веб-клиенте используют JS. Ужасный язык — но что делать!?

Вы, ради бога, пишите, на чем вам удобнее. Я, к слову, вас судить не пытаюсь. И искренне вам желаю удачи в том, что вы любите — разработке крупных проектов с ООП на чистом Си и игровых движков класса ААА с браузерами на C++. И никогда не разочаровываться в этом деле.

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

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

Слишком много разных причин, почему C++ нет в ядре Linux. От личной неприязни Линуса до тупой несовместимости. В LKML FAQ все расписано.

Хорошо оптимизированный код чаще красивее, чем что то неповоротливое.
Мои аргументы смахивают на мое мнение, поскольку им и являются. Я стараюсь опираться в споре на свой опыт. Гуглом могут пользоваться все.

А ваши аргументы смахивают на кучу расхожих стереотипов, подкрепленных расхожим оптимизмом. Если бы вы привели, как я,.пример из своего собственного опыта, это было бы интересно. А говорить «C++ крутой, потому что на нем кучу всего пишут» могу и я. Только вот я считаю, что основных причин его распространения 3.
1. Совместимость с Си
2. Свобода от патентных притязаний (вся платформа, стандарт и основные библиотеки полностью открыты)
3. Причина рекурсивная — моя любимая. C++ популярен оттого, что он популярен. На вопрос, на чем можно написать всё на свете, вопрошающему говорят: «Возьми кресты. Они сложные, но уж если освоишь, то удешь богом».

А еще — это соображение вас вряд ли убедит, поскольку оно уж совсем умозрительное, но я всё же скажу: чем универсальнее инструмент (а вы, надеюсь, не будете спорить, что в универсальности с C++ мало, кто может соревноваться), тем он менее удобен для каждого конкретного случая. В низком уровне мы превращаем C++ в Си, на высоком уровне мы пытаемся из него сотворить что-то наподобие C# или Java. Вот только Си проще и быстрее компилируется (просто за счет более простого синтаксиса), а в C# и Java более качественная защита от глупостей.

Хорошо оптимизированный код чаще красивее, чем что то неповоротливое


Где-то слышал фразу: «оптимизация — это то, чем начинают заниматься программисты, когда код слишком красив».

А если серьезно, то красив хорошо спроектированный код. На любом языке. Если хотите пример того, что я считаю красивым кодом, загляните в исходники Eclipse Platform. 15 лет истории и IBM как основной автор. Результат прекрасен. Его оптимизировали — но оптимизации носили именно архитектурный характер. И такие оптимизации лучше делать на Java — легче. А те оптимизации, о которых мы с вами говорили — это т.н. микрооптимизации — выиграть 10% производительности, чуть-чуть изменив последовательность выделения памяти и поменяв местами две командочки. Вот это я, простите, считаю суетой. Не интересно это.
Ну вот что за чушь вы несёте.
В низком уровне мы превращаем C++ в Си, на высоком уровне мы пытаемся из него сотворить что-то наподобие C# или Java.

Может вы так и делаете, но нормальные программисты используют С++ как С++. По долгу работы мне приходится использовать С#, Pyton, mel помимо С++, и на какждом из этих языков я пишу так как нужно писать на том или ином языке, никогде не писал на С++ как на С или на С#. Зато на предыдущей работе работал с людьми, которые писали на С++ как на яве, которые использовали огромные иерархии, и вместо указателей на функцию\метод использовали интерфейс IWorld, про переопределение операторов\шаблоны вообще неслышали, а для того чтобы добавить класс в фабрику приходилось править 5 файлов вместо того чтобы один раз написать макрос и шаблон, и использовать каждый раз в одном месте.

Вот когда пишешь на одном языке как на другом, вот тогда и появляются проблемы, возможно вы пытались в своей практике использовать С++ как С# или Java, отсюда у вас и все проблемы с этим языком.
Я очень жалею, что в Java нет переопределения операторов. Она бы стала лучше от этого.
Я очень жалею, что ни в Java, ни в C++ нет свойств. Без них код более унылый. В C++ я свойства эмулировал с помощью шаблонов и макроопределений, но это было не то…
Я очень жалею, что ни в C++, ни в C# нет внутренних нестатических классов. Более того, большинство людей, которые не исали на Java, даже не понимают, что это такое и для чего они могут быть полезны…

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

Но это всё — мелочи.

С точки зрения проектирования Listener в Java и event в C# — совершенно одно и то же (да, я знаю, что event-у можно назначить сразу несколько обработчиков, Listener тоже можно сделать таким, просто это — менее удобно). И многословность Java тоже не особенно приятна, но она компенсируется мощнейшими средствами IDE.

Все три языка на самом деле очень сильно похожи. Поэтому их можно и нужно сравнивать. И сравнение это будет явно не в пользу C++, когда дело касается надежности кода. Единственное, чем C++ может похвастаться — это отсутствием дополнительного runtime-а для исполнения кода.

И еще.

Я сначала изучил C++ (по крайней мере на уровне книги Герберта Шилдта), а только потом появился язык C#. А про Java я вообще узнал только 5 лет назад.

Почему вы считаете, что если для меня эти языки похожи, я не понимаю между ними разницы? Давайте просто допустим, что эта разница несущественна.
Но это всё — мелочи.

Вообще не понимаю к чему вы привели эти примеры, я говорил не про фичи конкретных языков а про процесс проектирования приложения. (и да внутринние классы в С++ это friend классы, ну и да всё что вы привели фигня, единственное чего не хватает С++ это рефлекшена)
С точки зрения проектирования Listener в Java и event в C# — совершенно одно и то же

Ну вообщето далеко не одно и тоже, Listener в яве требует наследования от интерфейса. Отсюда в яве рождается куча ненужных однострочных интерфейсов, либо же интерфейсов при реализации которых приходится писать пустые функции, в С# же и в С++ этого можно избежать. Программисты на проекте были java way, а потому использовали интерфейсы, а т.к. городить кучу интерфейсов им было лен, они решили использовать С стиль и передавать идентификатор и указатель на войд. Вот что в нашем случае означало писать на С++ как на яве и как на С, и именно из-за вот таких вот «решений» вырисовываются поистине эпические ошибки, патерны это конечно хорошо, но их тоже нужно уметь и писать и применять, в зависимости от языка.
И многословность Java тоже не особенно приятна, но она компенсируется мощнейшими средствами IDE.

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

Все эти три языка на самом деле сильно разные, пичально что вы это не видите. Каждый из этих языков затачивается под свои задачи, да они пересекаются но не так часто как вам кажется.
Единственное, чем C++ может похвастаться — это отсутствием дополнительного runtime-а для исполнения кода.
А ещё скоростью, а ещё мультиплатформенностью, а ещё гибкостью в плане управления памятью, гибкостью в оптимизации, и тд и тп.
Почему вы считаете, что если для меня эти языки похожи, я не понимаю между ними разницы? Давайте просто допустим, что эта разница несущественна.

Вы не понимаете между ними разницы, потому что вы считаете что эта разница несущественна.

Я сначала изучил C++ (по крайней мере на уровне книги Герберта Шилдта), а только потом появился язык C#. А про Java я вообще узнал только 5 лет назад.

А я начинал с Delphi а после 5 лет когда поступил в универ познакомился с С++ (на уровне книг Страуструпа, Майерса, Александреску) и прочими языками, а после 5 лет обучения на этих языках в универе, я 6 лет работаю с С++, и попрежнему продалжаю учится программированию. Только вот я не понимаю как эта информация поможет вам? Также как не понимаю зачем вы это написали мне.
Окей. Давайте тогда я тоже вспомню, что в школе программировал на Delphi. А когда увидел C++, он мне показался очень запутанным и неудобным. Учить я его начал в первую очередь именно потому, что не видел альтернативы. Когда появился C#, я эту альтернативу увидел. Но я еще достаточно долго пытался иногда писать программы на C++ целиком. Всякий раз получалось хлопотно и времени уходило больше, чем на C#.

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


Серьезно? Вот уж я не знал! Последние 3 года пишу сперва под Android, сейчас портирую яву на новую платформу, был даже контрибьютором в стандартную библиотеку альтернативной Java-машины Avian и — ужас — не знал, что Listener — это анонимный локальный класс.

Вы понимаете, что с точки зрения архитектуры приложения не имеет значения, создается в данном месте анонимный класс, указатель на функцию, определенный через typedef или делегат? Ну не важно это. Главное — что тут имеет место механизм callback-а.

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

Конечно они разные и я это вижу! Но если вы мне дадите программу на C#, я переведу ее вам на Java, воспользовавшись терминами Java и использовав ее преимущества, но программа при этом почти не изменится. То же самое можно сказать про C++. Только там будет сложнее с низкоуровневым дизайном, поэтому кусок кода, возможно, придется загнать под JNI (и эффективнее).

Вы не понимаете между ними разницы, потому что вы считаете что эта разница несущественна

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

Был C++. Мощный и универсальный, но местами неудобный, опасный и кривой. Люди, которых он раздражал, сделали Java, чтобы не спотыкаться о проблемы с памятью и избыточную сложность. Получилось лучше, но они выпилили кучу полезных вещей. Поэтому люди, которых Java задолбала «необходимостью имплеменировать целый интерфейс», которую я и назвал излишней многословностью, а также некоторыми другими своими недостатками, создали C#.

Большая часть ваших аргументов (про скорость и управление памятью) верна. Это — те причины, по которым я часто использую JNI. Но вот это:

а ещё мультиплатформенностью

насмешило. Честно. Я лет пять искал способ научиться написать проект на g++ так, чтобы потом нормально собрать его под Windows. Или вы мне сейчас начнете про ANSI рассказывать? Давайте я тогда вам в ответ расскажу про прекрасный модификатор «b» в fopen, который, если забыть его на Windows, приведет к тому, что из вашего прочитанного бинаря волшебным образом исчезнут все символы с кодом 13. Я как-то долго отлаживал кусок libcore, который портировал с Linux на Windows и не мог понять, почему у меня картинка не читается с диска. Повеселился на славу.

Единственный по-настоящему кроссплатформенный язык в этой тройке — это Java. И то только если вы используете «родную» библиотеку классов от Oracle. Возьмите стек технологий, на которых основан eclipse — будет вам мультиплатформенность.

Только не надо мне говорить про Qt. Как только он станет частью C++ или хотя бы обзаведется лицензией, позволяющей его использовать в проектах любой степени коммерциализованности без всяких приседаний перед авторами и выплат, я рассмотрю его как приемлимую альтернативу. Кстати, в нем есть кроссплатформенные файловые потоки?
Окей. Давайте тогда я тоже вспомню, что в школе программировал на Delphi.

Вы хотя бы до конца комментарий прочитали? Зачем вы пишите эту инфу???
это анонимный локальный класс.

И что? От этого не изменится тот факт, что этот класс должен реализовывать интерфейс.
Вы понимаете, что с точки зрения архитектуры приложения не имеет значения, создается в данном месте анонимный класс, указатель на функцию, определенный через typedef или делегат? Ну не важно это.

В том то вся и фишка, что важно, каждый элемент должен выполнять свою функцию.
Конечно они разные и я это вижу! Но если вы мне дадите программу на C#, я переведу ее вам на Java, воспользовавшись терминами Java...

Практически любой код, на любом языке, можно переписать на другом, но это не значит что языки похожи, каждый язык используется там где он нужен, я могу дать вам кусок рендера на С++, но когда вы его перепишите то получится что 80% кода будет написано на JNI, и какой тогда смысл брать яву?
Я умею использовать все эти три языка

Не видно, судя по той чуше что вы пишите, вы знаете только яву.
Я лет пять искал способ научиться написать проект на g++ так, чтобы потом нормально собрать его под Windows.

мда, это говорит лишь о ваших способностях, а не о языке.
Давайте я тогда вам в ответ расскажу про прекрасный модификатор «b» в fopen

В очередной раз хотите похвастаться своей безграмотностью в С++? Я не против. ))
Единственный по-настоящему кроссплатформенный язык в этой тройке — это Java. И то только если вы используете «родную» библиотеку классов от Oracle. Возьмите стек технологий, на которых основан eclipse — будет вам мультиплатформенность.

Не видел ни одного примера, на яве для IOS, xbox, ps. И где ваша хвалёная мультиплатформенность?
Только не надо мне говорить про Qt.

Если бы я говорил про какую-то универсальную библиотеку то я скорее взял бы буст.
Кстати, в нем есть кроссплатформенные файловые потоки?
Есть, а чем вам не угодили потоки из stl?
UFO just landed and posted this here
В очередной раз хотите похвастаться своей безграмотностью в С++? Я не против. ))


Нет. Просто мне попал в руки кусок кода на C/C++, который был написан для Linux и который надо было портировать на Windows. Увы, код был написан безграмотными разработчиками из компании… как бишь ее… Google, кажется, которые не знали про потоки в stl.

Лично мне потоки из stl не нравятся двумя вещами: во-первых, они неудобны, во-вторых — медленны. Возможно, так же считали и люди, делавшие backend в libcore.

Не видел ни одного примера, на яве для IOS

А вы знаете, какие титанические усилия Apple прикладывает к тому, чтобы не пустить Java на iOS? Они этой конкуренции боятся как чумы. Потому что весь стек технологий (XCode etc.) в подметки не годится оному из Java.
UFO just landed and posted this here
Иск Оракла Гугл вполне успешно отбил по всем пунктам, кроме сущей ерунды. Никто не может «приватизировать» API. Можно считать проприетарной только реализацию.

То, что можно некроссплатформенный код писать на чем угодно, я согласен. Но не нужно подменять понятия. Я вам сказал, что Java кроссплатформенна, поскольку на ней надо очень постараться, чтобы написать что-то платформо-специфичное. А если ограничиться чисто Java-инфраструктурой (а там есть очень-очень много кода и от apache foundation и от куч других), то вообще почти невозможно. Конечно, это не отменяет дураков, которые в Java-коде прибавляют бекслеши к путям. Тут уж ничто не поможет.

Зачем надо, чтобы вся инфраструктура была стандартизована и являлась частью набора инструментов разработчика? Ответ очень простой — чтобы не было зоопарка. Один станарт — один подход — меньше всего изучать. К тому же, чем меньше кода, тем выше его качество. Этим сильна Java. На ней редко кто-то пишет то же самое по второму разу. Просто такая культура.
UFO just landed and posted this here
А вот этого я не понимаю, серьёзно. Это же так прекрасно, изучать что-то новое! В этом весь смысл и весь кайф!

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

Я люблю изучать то, что интересно, а не всё подряд. И люблю стабильность. То есть если не хочется писать всё from scratch, то берешь качественно сделанную платформу и не лезешь в нее. По крайней мере, на первом этапе разработки. Понимаете?

А еще больше я люблю создавать, а не изучать. Как говорится, чукча не читатель…

И звучит для меня, если честно, примерно как «меньше производителей на рынке — выше качество продукта».

Странное сравнение. Когда кода мало, а вылизывают его сотни разработчиков, он становится безупречен. Пойдите, попробуйте найти ошибку в ecj, например. А ведь это — компилятор — довольно непростая штука.

А если бы компиляторов Java было не 2, а 20 (как у Питона, например), то усилия всех этих людей были бы распылены на них и каждый в отдельности был бы хуже.

В open-source, где в любой момент код можно беспрепятственно форкнуть, конкуренция — зло. Такая вот «коммунистическая» идеология.
UFO just landed and posted this here
Почему-то такого опыта у меня нет. Не поделитесь своим? Просто ради интереса.

Да на здоровье. Взял я как-то Android Libcore. И решил собрать его под Desktop. В нем кучка разных кусков — там и makefile, и autotools и еще кое-что. И всё это надо настроить, пропатчить…

Ладно, черт с ним. Дорботали напильником, собрали, потом месяц учили его работать под Win32 (читайте выше историю про «b» в fopen), а потом надо было эту всю хрень сцепить с еще одним куском кода, который собирался уже с помощью cmake.

Хорошо, что там хоть scons нигде не было… Понимаете? Если бы система сборки была одна, то я бы в худшем случае ее одну знал и настраивал, а не скреплял кривыми костылями кучу makefile-ов.

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

Дело в том, что желание «пилить экзотику» обычно возникает либо у студентов-экспериментаторов, либо у людей, недовольных мейнстримом по каким-либо объективным причинам. По лицензионным. По политическим. Или просто по причине неисправимой косячности этого мейнстрима.

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

А сколько в мире дистрибутивов Linux под десктоп? Их сосчитать не могут — даже те, у которыхбольше одного мейнтейнера. И, кстати, по мере «взросления» дистрибутива Ubuntu, он перетянул на себя внимание большей части Linux-пользователей и разработчиков, поскольку вложить силы во что-то популярное, согаситесь, приятнее.

Вот у Java был официальный компилятор. IBM он не устроил своей лицензией (и, видимо, имевшимися в тот момент хилыми возможностями), и они написали ECJ. Теперь компилятора два. Между ними есть различия и опытные разработчики их знают. ECJ строже к стандартам, но при этом он умеет делать классы из синтаксически некорректных файлов. А еще он быстрее.

И хотя Java по популярности обгоняет почти все остальные языки, для нее до сих пор ровно 2 компилятора. И я нигде не слышал, чтобы кто-то пытался сваять третий. Зачем? IDE — как минимум три штуки. А компилера — 2.

А теперь подсчитайте, сколько на свете компиляторов C/C++ под одну только платформу x86. Не учитывайте устаревшие и заброшенные — берите только актуальные. Пальцев не хватит сосчитать.

Кстати, JVM достаточно много, но как правило они пишутся по одной из двух причин: оптимизированность под конкретное железо и лицензионные соображения. И обычно тоже максимум 2-3 штуки на платформу. Потому что там всё (относительно) просто и ясно. Что еще улучшать?

Я не утверждаю, что Java — свет в окошке, а C++ надо выкинуть. Просто степень доработанности Java как инфраструктуры значительно выше, хотя она заметно моложе, чем C++. Ее лучше спроектировали.

есть вариант «не пилить ничего»

Нет этого варианта. Дорабатываются open-source проекты в основном по одной и той же практической причине: вам нужна функциональность (исправленная бага), а автор ушел в запой на месяц. А если вы допиливаете столько, что вам начинает казаться, что работаете вы больше него, то вы делаете форк. И никуда вы не денитесь от этого. Можете только закрыть свой проект или оставить открытым (если не GPL). Вот и весь ваш выбор.
UFO just landed and posted this here
С++ еще у (Open) Watcom есть. Но там есть проблемы с развитием. А когда то был лучший набор для C/F77.
UFO just landed and posted this here
В очередной раз порадовался, что я разрабатываю под линуксом, установку всяких опенсорс-решений за меня делает пакетный менеджер, и так далее.

Вот тут вы меня заставили улыбнуться. Я уже несколько лет не разрабатывал что-либо не-кроссплатформенное. И выработал-таки себе toolchain, позволяющий писать на C/C++ кроссплатформенные приложения с UI на JVM, при этом не используя не только проприетарные решения в готовом продукте, но и GPL. Только MIT, BSD и Apache.

Какой смысл писать программу, которая зависит от конкретной платформы или от прихоти держателей Виндоуса или Мака. Так ведь :)

Вы так говорите, будто это что-то плохое.

Я не считаю, что быть студентом-экспериментатором — плохо. Просто я не рассматриваю всерьез их вклад в развитие индустрии. (Я допускаю, что есть вундеркинды, но в среднем они должны сперва научиться, чтобы начать делать что-то полезное).

Ну, как минимум, IcedTea ещё.

IcedTea не содержит в себе компилятор. Вот выдержка с оф. сайта:
The aim of the IcePick [часть IcedTea] project is to allow the language tools (javac, javadoc, javah, javap, apt) from the OpenJDK project to be built separately using any 1.5 compliant Java compiler.

Вот это — «any 1.5 compliant Java compiler» намекает, что компилятор надо взять где-то снаружи. Хотя я сам не работал с IcedTea, гарантии дать не могу.

А вот ECJ я разбирал вплоть до исходников. И он как раз и является единственным известным мне компилятором Java, кроме javac от Oracle. Хотя википедия его не приводит, а приводит ныне покойный GCJ, который вы, видимо, считаете полноценным компилятором, которым он не является в силу ограничений интроспекции, несовместимых с мало-мальски продвинутым JVM-кодом. Потому, кстати, и заброшен. ECJ, кстати, — структурная часть Eclipse. Я выше уже писал…

Хватило, даже одной руки: clang, gcc, icc, ну и cl.exe ещё, вероятно.

Куча их: вот. Хотя их надо все палочкой потыкать на предмет свежести.

Вышеприведённый мой опенсорс-проект недоступен под убунтой

Я сейчас обидную вещь скажу. Хотите популярности вашего продукта — будьте на виду. И сделайте то, чем легко пользоваться везде. Даже специалисты, когда есть выбор, предпочтут из двух конкурирующих технологий (при равных возможностях) ту, которая в их ОС устанавливается одним «apt-get install». Такой уж закон в наших с вами «джунглях». Хотя, он нарушается, если вы ваяете что-то настолько уникальное в смысле предметной области, что ради этого не влом ставить какую-то экзотическую ОСь.

для хаскеля… из мейнстримных

Посмотрите вот сюда. Вас же не удивит, например, что для Go и CoffeeScript только один компилятор? Просто уровень популярности Хаскелля таков, что при том уровне требований, которые к нему предъявляются, в основном компиляторе не было найдено ни одного принципиального изъяна.

В мейнстриме одним единственным компилятором могут похвастаться только Ruby (очень классный язык, учитывая, каких на нем монстров люди ваяют в одиночку) да PHP, «неповторимая глюкавость» которого не позволяет создать альтернативную имплементацию.

И, кстати, я не считаю, что хаскелль плох. Я не могу так считать, поскольку почти не знаком с ним. Но я знаю, что он — не для мейнстрима. Он, по сути, — язык «для гиков». Разве нет?

Думается мне, фортран гарантированно проще, старше и так далее, чем C++, но почему-то компиляторов у него тоже немало.

А вот здесь я даже не знаю, что вам сказать… Вы, наверное, не видели фортран. А я знаю по меньшей мере трех людей, кто пишет на нем профессионально несколько лет. Двое из них — это моя жена и мой отец (жена — физик-теоретик, отец — инженер). И могу сказать, что более ужасно нагороженного (слово «спроектированный» здесь никак не подойдет) языка даже представить себе нельзя. В качестве примера фортрановского безумия люблю приводить то, что все переменные во
все
функции по умолчанию передаются по указателю. Это делает отладку больших проектов просто феерической, особенно, если учесть, что многие Fortran-разработчики пользуются этой «милой особенностью» как полезной функцией.

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

Вариант бросить любимое дело и пойти играть в нарды я не рассматриваю здесь. Это был бы явный оффтоп.

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

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

Я видел. Очень хороший язык для математических задач.
Очень хороший язык для математических задач.


C# — очень хороший язык для математических задач. Быстро считает, безопасный, легко создать UI при желании и необходимости, есть переопределение операторов и хорошие исключения. Maple — хороший язык для математических задач. Умеет доказывать теоремы и решать уравнения аналитически. MatLab — неплохой язык для работы с большими массивами данных. C++ — приемлимый язык для математических задач, если «умеешь его готовить». Просто потому что исключительно быстрый и позволяет абстрагироваться.

Сам я использовал (в большей или меньшей степени) всё это, когда учился, и немного после этого.

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

Я не верю, что вы найдете хоть одного человека, которому было бы менее сорока лет, который бы умел программировать, который бы знал хотя бы пару из приведенных технологий, и который бы при этом защищал Фортран. Во всяком случае, на факультете ВШОПФ в Нижнем Новгороде, где я учился, таких не было.

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

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

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

В любом случае я эту дискуссию продолжать смысла не вижу.
Действительно, смысла нет. У вас мания преследования, и я не желаю ее развивать.
Идеальный языки для прототипирования математических задач это, имхо, Python :). Шарп и плюсы проигрывают ему со свистом в обилии легкодоступных инструментов и удобстве их использования.
UFO just landed and posted this here
Ну, я тоже не переношу динамически типизированные языки и был сильно против питона пока не попробовал :). Прямо в консоли половину дел можно сделать. А раньше думал — зачем питону этот режим консольного интерпретатора? Оказывается в массе случаев — крайне удобно. Есть такая софтика Spyder — по сути сборка питона с простенькой IDE и расширенным набором библиотек из коробки, и там очень неплохо эта тема обыграна. На большие проекты естественно отмасштабировать будет трудно, но до 10k строчек работает вполне комфортно и для прототипирования — самое оно.
Если вы можете удержать всю логику программы в голове одновременно, то всё равно, на чем ее писать и как. Где синтаксис привлекательнее, на том и пишите.

А если задача серьезная, то создавать ее надо начать с того, чтобы посидеть дня три (или неделю) над моделью и над архитектурой. А когда вы ее придумаете, вряд ли вы среди питона и C# выберете питон (при равном уровне квалификации).
Я же написал — «для прототипирования».
Нормальные задачи естественно требуют подумать над моделью и архитектурой.
Шарп тут кстати между сциллой и харибдой оказывается — для прототипирования удобнее питон, для нормальной реализации — плюсы. А шарп — ни рыба и ни мясо.
Про легкодостпные инструменты, я бы поспорил. Я сравнивал PyCharm с Eclipse CDT и CDT была намного мощнее. Хотя, конечно, Python надо сравнивать с C# и Java, а не с C++. Разная весовая категория…
Мощность и простота использования — разные вещи. Мощная IDE с богатыми возможностями для рефакторинга, юнит тестирования и проектов на десятки тысяч файлов для прототипа мне нужна как собаке пятая нога. А вот удобный и простой рантайм где все правится на лету, богатейшие по функционалу и подключаемые в одну команду библиотеки, плюс приличное количество примеров использования в Сети оказываются очень к месту.
UFO just landed and posted this here
Пардон, не дочитал:

Если бы мне внезапно запретили писать мой IM-клиент, я бы не пошёл дописывать Psi или Pidgin, я бы пошёл заниматься матаном.

А задайтесь вопросом, откуда у вас вообще возникло желание написать свой IM «с блекджеком...» У меня, кстати, такое желание тоже периодически возникает! И я знаю, почему. Точно знаю.

Причина в том, что имеющиеся меня не устраивают. Они по большинству своему ненадежны, некроссплатформенны, коррумпированны или платны. Вот и притягивает эта задача девелоперов как огонь мотылька. Чем большее число пользователей не устраивает имеющаяся ситуация — тем больше «пильщиков».
UFO just landed and posted this here
Мне тоже нравится. Вам всё равно, какой код писать? Мне — нет. Я пишу тот код, который мне интересно писать. И полагал, что вы поступаете аналогично.

Я же не изучал «фокус-группу». И маркетинговые исследования не проводил. Просто я осознаю (предполагаю), по какой причине мне хочется того или иного. Стараюсь понимать причину своих устремлений. Это полезно.
UFO just landed and posted this here
Chaos_Optima,
С точки зрения проектирования Listener в Java и event в C# — совершенно одно и то же
Ну вообщето далеко не одно и тоже
Извините, что вклиниваюсь в ваш жаркий спор, но таки мне самому интересно.
Listener в яве требует наследования от интерфейса.
Ок.
в С# же и в С++ этого можно избежать.
Ок.

И таки в чём принципиальная разница? И там, и сям паттерн Listener. В Java он многословный, а чтобы подписать несколько колбэков, нужно сгородить собственный адаптер (каюсь, могу не знать, есть ли в стандартной библиотеке что-то уже готовое). В C# паттерн встроен в язык, оттого он и проще.

Оппонент вам пишет, что в одном и другом случае, это механизм колбэков — вызов чего-то там в ответ на произошедшее событие. Реализация — разная, смысл — один.

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

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

Принципиально разницы нет. Разница в проектировании и реализации, если реализовывать этот патерн в С++ как на яве то код усложнится, отсюда и последствия (на своём опыте столкнулся с этой проблемой). Критика была не в сторону того что лиснер в проекте на яве нужно использовать, а в проекте на С++ не нужно. Критика изначально была в том, что на С++ не нужно писать как на яве.
Критика изначально была в том, что на С++ не нужно писать как на яве.

Покажите мне, где я вам сказал, что в C++ НАДО писать как в Java. Я такого не говорил ни разу.

Я говорил, что C++ на высоком уровне принимает парадигмы и вид, очень сильно напоминающий Java, только без кучи ее плюшек и защиты. Понимаете? Универсальность влечет за собой понижение комфорта исвользования в каждом конкретном случае. Молоток с одной стороны, отвертка с другой, перочинный нож вместо рукоятки. Удобно пользоваться?

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

Кстати, недавно увидел классный язык, почти всем мне нравящийся (кроме мелочей). Он на JVM, то есть Java-совместим в нем есть свойства, переопределяемые операторы, константная корректность… Жаль, что там отказались от checked exceptions (это — одна из мощнейших фич Java, по-моему). Kotlin называется. Видели?
Если вопрос не мне, то считайте что это ответ в пустоту :)

Слышал про Котлин и про Скалу. Но не имел дела с ними.
Взять тот же Андроид — надеюсь, на них можно под него писать, поскольку голая Java (а на андроид она ещё и без лямбд!) лично у меня вызывает мгновенное оторжение из-за многословности и топорности. Listener — хороший тому пример.

P.S. Си-шарпщик.
Котлин — наверняка поддерживается. Так как сейчас Гуглы взяли в основу Android Studio платформу IntelliJ, а именно эти ребята его придумали, думаю, проблем нет. Там же только компиляция, по сути, отличается. Хотя API рассчитана на Java…
Из своего опыта я приводил уже пример где то ближе к стволу дерева.

Я просто приводил общеизвестные факты.

Как раз популярность C++ и кроется в его универсальности.

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

А если серьезно, то красив хорошо спроектированный код

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


Ну слава макаронному монстру, хоть в чем-то договорились!

C++ несовместим с C в смысле своих возможностей. И необходимости писать extern «C», чтобы избежать name mangling-а. И еще пара мелочей… Ну и что? Всё равно когда вам нужен очень-очень эффективный код, вы перестанете использовать vector и возьметесь за старый добрый int[]. Возможно, вы вместо malloc, напишете new. Не исключаю, что в суперэффективном коде у вас пару раз проскочит какой-то класс. Но в основном это будет код на Си. Потому что высокоуровневые абстракции едят производительность. Вы не можете даже полиморфизм толком использовать, потому что vtable — это лишний резолв указателя при каждом вызове функции. Всё, что останется от C++ — это статические касты… и C. Вот такой нижний уровень.

А на верхнем уровне вы упретесь в необходимость либо линковать код в один бинарь, либо бить его на кучу динамических библиотек. Компиляция долгая… ОЧЕНЬ долгая (привет Джаве, где строятся отдельные class-файлы в проекте любого масштаба). Ошибки связывания, необходимость указывать библиотеки глупому линковщику в правильном порядке. Сборочная система CMake хороша, но ее придется учить. Старый-добрый make требует написать целую программу, которая соберет вашу программу. А про autotools я и говорить не хочу…

Я честно не знаю, о чем думал человек, придумавший разделение на .h и .c/.cpp файлы в виде простого включения одних в другие. Даже в древнем Turbo Pascal-е линковщик был умнее.

Эти недостатки общие для С и C++, но на C все-таки редко пишут проекты, содержащие 1000 файлов. (Пишут конечно, но это — вообще ад кромешный). А С++ на это всерьез претендует — так почему бы хоть сборочную инфраструктуру не включить в стандарт языка, как это сделано в Java и C#?

О такой мелочи как аналог JavaDoc я и говорить боюсь…

Мало аргументов?

Теперь я спрашиваю: представьте, что лично вы, в одиночку, собираетесь создать серьезный проект с интересной математикой и сложной бизнес-логикой. Скажите мне, неужели вы станете писать управляющий код на C++? Или, всё же, ограничитесь математическим backend-ом, а контроллеры и UI напишите на чем-то более приемлемом?

Может быть, я что-то серьезно не понимаю…
сё равно когда вам нужен очень-очень эффективный код, вы перестанете использовать vector и возьметесь за старый добрый int[].

Эм… зачем, когда есть array. Ну и да внутри vector и int* по большей часть одинаковые.
Вы не можете даже полиморфизм толком использовать, потому что vtable — это лишний резолв указателя при каждом вызове функции.
Лол, как будто в C# и Java это делается по другому)). Ну и да современные компиляторы, когда могут точно определить класс не прыгают по vtbl.
Всё, что останется от C++ — это статические касты… и C. Вот такой нижний уровень.

А ещё шаблоны, ссылки, raii, инкапсуляция, лямбды, constexpr, auto, decltype и куча других приятных мелочей.
Ошибки связывания, необходимость указывать библиотеки глупому линковщику в правильном порядке. Сборочная система CMake хороша, но ее придется учить.

И правда IDE то у нас нет, приходится всё ручками в консоле компилить, и даже CLion не умет правильно cmake генерировать.
О такой мелочи как аналог JavaDoc я и говорить боюсь…

Действительно, ведь так мало средств для документации С++, даже доксигена нет.

Прежде чем писать очевидно непродуманные утверждения, было бы неплохо хотя бы 5 минут посидеть и погуглить эти вопросы, чтобы не нести чушь. Единственное в чём вы оказались правы так это в отсутствии модульности в С++, это и правда серьёзный недостаток, который я надеюсь попытаются решить.
Лол, как будто в C# и Java это делается по другому)).

Я не говорил, что писать в этом случае надо на Java. Я считаю, что в этом случае вполне можно писать на Си.

И правда IDE то у нас нет

Есть, конечно, но имеющийся большой проект, например, вы в IDE замучаетесь засовывать. Люди изобрели столько разных сборочных систем для C++, что со всем этим зоопарком просто не разобраться. В данном случае в первую очередь надо думать о legacy, конечно. В вашем собственном проекте вы найдете приемлимую настройку (хотя, привязывать проект к одной IDE — это не комильфо).

так мало средств для документации С++, даже доксигена нет

Я, честно говоря, не в курсе — а есть IDE, которая из комментариев Doxygen делает контекстную подсказку при вводе кода?

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

было бы неплохо хотя бы 5 минут посидеть и погуглить эти вопросы

Единственное в чём вы оказались правы так это в отсутствии модульности в С++

Разница между мной и вами в том, что я просто имею более высокую планку требований к инструменту. Вас устраивает поддержка CMake в CLion и вы считаете, что это удобно. Я считаю, что должен либо знать сборочную систему досконально сам, либо она должна быть одна, стандартная и поддерживаться ВЕЗДЕ. А желательно — и то, и другое разом. Я уже 13 лет занимаюсь программированием профессионально и за это время мне порядком надоело иметь дело с недоработанными и неудобными инструментами. Даже если они мощные. Только и всего. К примеру, когда я знаю, что мой проект собирается только в одной конкретной IDE, только под одной ОС или я не знаю, как он собирается, я этого не терплю.
Я не говорил, что писать в этом случае надо на Java. Я считаю, что в этом случае вполне можно писать на Си.

Эм… то есть когда нужен полиморфизм, нужно использовать С? 0_о не думаю что вы могли бы дискредитировать себя сильнее чем сейчас.
Есть, конечно, но имеющийся большой проект, например, вы в IDE замучаетесь засовывать.

0_0 wat? Я ошибся, вы всё таки умудрились дискредитировать себя ещё сильнее.
Я, честно говоря, не в курсе

Поэтому я вам и советовал погуглить прежде чем чушь писать
а есть IDE, которая из комментариев Doxygen делает контекстную подсказку при вводе кода?

Да Visual Studio.
Просто он не является частью стандарта — это лишь костыль

эм… ну во первых, зачем эта вещь в стандарте? Ну а во вторых вы считаете что всё что не является частью стандартной библиотеки, а расширяется извне это костыль? 0_о
Разница между мной и вами в том, что я просто имею более высокую планку требований к инструменту.

Нет. Разнится между мной и вами лишь в том что вы не знаете инструмент, который осмеливаетесь критиковать, и что печальнее не хотите его изучить, хотя бы на приемлемом уровне.
UFO just landed and posted this here
Не знаю как у вас, но у нас на нижнем уровне нужен высокий уровень абстракции. Если бы было удобнее написать на C, написал бы на нём. Нижний уровень не требует урезания инструментария, но требует эффективного использования оного. Конечно приходится некоторые библиотечные функции замещать своими, но это касается и C, так как не все функции имеют варианты для целочисленной математики.
Мой большой проект, написанный с нуля, не страдает от того, что обе части написаны на C++. Время компиляции занимает 10 минут для шести целевых платформ. Проблем с порядком библиотек также не замечал.

Я люблю Doxygen. Есть ещё варианты.

Проблем с Autotools и make тоже не вижу. Ещё есть qmake, b2. Вы лучше подумайте, чем и как собирается java runtime.

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

Не вижу беды в 1000 файлах, если оно так нужно. Ведь для каждого правила сборки писать не надо.

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

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

Я люблю Doxygen. Есть ещё варианты.
Проблем с Autotools и make тоже не вижу. Ещё есть qmake, b2.


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

Вы лучше подумайте, чем и как собирается java runtime.

Подумал. И даже собирал OpenJDK. Жутко он собирается. Сложно, разношерстно и долго. Но, к счастью, человек, пишущий на Java, а не саму Джаву, лишен необходимости заниматься подобными вещами.

А вот Java-код собирается всегда одинаково. Класс файл на один исходник. Файлы лежат по структуре, совпадающей с именами пакетов. Сборка осуществляется путем «компилятор, возьми все эти Java-файлы и все эти jar-библиотеки и сделай мне .class вот сюда».

Тут не с чем разбираться и не в чем путаться. Я могу взять любой Java-проект любой сложности и, если у него нет нативных расширений, собрать его буквально одной командой. И, к счастью, разработчикам обычно не приходит в голову изобрести еще одну САМУЮЛУЧШУЮ систему сборки для Java.

Кстати в обоих языках можно жить без заголовочников (кроме системных

Это, простите, как? Инклюдить один сырец из другого? Быстрая у вас, однако, сборка будет…

Не вижу беды в 1000 файлах, если оно так нужно

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

Тот самый проект, про который я писал ближе к стволу дерева. К сожалению, код я вам показать не могу по понятным причинам. Конечно все там можно было написать на голом C, с применением ООП, но проект изначально разрабатывался на C++/boost, да и одним из основных критериев были сжатые сроки.

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

И, к счастью, разработчикам обычно не приходит в голову изобрести еще одну САМУЮЛУЧШУЮ систему сборки для Java.

Вы забываете, что Java компилируется в платформонезависимый байткод и там только Java. В простых проектах на C или C++ тоже достаточно небольшого Makefile, который вам все соберет на любой платформе одной командой make. Но если начинает пахнуть такими вещами как «Платформозависимый код» или «кросскомпиляция» и кучей зависимостей, то Makefile уже не позволяет все это упростить. Именно поэтому были сделаны Autotools, которые сгенерят configure и некоторые шаблоны к нему, удовлетворяющие среде сборки, а при запуске configure вы уже настроите все под целевую платформу.
Конечно, если зависимостей не очень много и проект не очень крупный, то всё равно можно обойтись и одним Makefile, который будет настраиваться через переменные окружения. Да, приходится платить временем для создания конфигурации управления зависимостями, но производительность конечного продукта этого стоит. Лично я пользуюсь qmake. В заговорили о стандартах? Извините, это универсальные инструменты, которые могут собрать проект, если он написан на всех возможных языках сразу. Если вдруг для C/C++ появится стандартный для всех реализаций инструмент, то эти системы все равно останутся и будут использовать этот новый инструмент.

Это, простите, как? Инклюдить один сырец из другого? Быстрая у вас, однако, сборка будет…
Это плохая техника, но она применяется ( привет средам типа IAR ). Для компиляции указываются только конечные потребители кода.

Но этой кучей должно быть легко управлять

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

Смотрим в исходник IntelliJ IDEA. Там есть Java, Groovy и Kotlin. А еще куча всякой интересной модульности. И всё это собирается прямо из той же самой IDE. Хотя чести ради надо сказать, что из консоли для сборки нужен gradle. Но gradle, в отличие от большинства сборочных систем для C/C++, устроет так: пишешь «вот тут у меня Java, тут Kotlin, тут ресурсы, результат положи, пожалуйста, сюда и запакуй в jar с вот таким именем». И на этом вся конфигурация заканчивается.

Eclipse, правда, собирается с помощью чуть более сложного Maven-а, но он — уже сборочная система, которая считается Enterprise-решением. Им пользуются матёрые джависты в проектах, для которых используют монстров типа Spring Framework.

Кстати, полный объем исходных кодов Eclipse Platform составляет примерно 2 гигабайта. Это именно исходники. Результат (со всеми установленными плагинами) будет мегов четыреста. И этот монстр довольно легко правится, отлаживается и дорабатывается. Такие вот масштабы.
Думаю, спор надо прекращать.

Я весьма посредственно знаю C++ на уровне крупных Enterprise-проектов.

Вы, по всей видимости, практически не знаете Java.

Каждый любит то, что знает (или, наоборот, знает то, что любит)
Вообще многие ваши высказывания заставляют меня думать, сто C++ и C вы весьма поверхностно знаете.
C++ я действительно знаю поверхностно. На уровне стандарта 98 года. Qt, Boost не знаю, да. Первый слишком проприетарен, чтобы мне хотелось его использовать для себя, а по работе не приходилось. Второй слишком заморочен.
Учился C++ на работе я, дорабатывая ОС Symbian.

А вот Си знаю вдоль и поперек. Хотя в проектах на «Си с ООП», слава богу, не участвовал уже 4 года. Если быть совсем честным, то обычно я «скоростной» код пишу на C++, ограничивась функциональной парадигмой. То есть использую new/delete вместо malloc/free. Контейнеры использую по минимуму.
UFO just landed and posted this here
Императивная парадигма от функциональной отличается отсутствием глобального состояния. Пишите «чистые» функции и будет вам счастье. Что я упустил?
UFO just landed and posted this here
И локального тоже.

Я там, выше по дискуссии, писал, что ФП — вещь тяжело усваиваемая. Я, конечно, как человек, плохо его знающий, не имею права его критиковать, но всё же…

Я точно знаю, что такое состояние системы и откуда оно берется. Философская концепция, лежащая в основе ООП, мне понятна и я, при желании, могу объяснить ее 6-летнему ребенку.

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

(к слову, если логгер передавать среди аргументов функции, то логгирование возможно и в ФП-подходе, так? Только, правда, я с детства приучал себя передавать в функции как можно меньше параметров)

без хорошей, развитой и мощной системы типов

То есть без классов? Или вы про какие типы говорите? Что-то я запутался…
UFO just landed and posted this here
А может быть, продецурную вместо объектно-ориентированной?
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
С тех пор, как среди сложных задач находится математическое моделирование физики, управление сложными системами и прочий код, который имеет предметную область, требующую нескольких лет в профильном ВУЗе, помимо, собственно, умения программировать.

Вот вам пример сложной программы, например: en.wikipedia.org/wiki/NWChem
Моделирует квантовые состояния и переходы в атомах. В частности. И много чего еще другого.

Думаете, приведете в пример UI сопоставимый по сложности?

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

Да без проблем, возьмите любой браузер и скажите, есть ли среди них хоть 1 который поддерживает html5 полностью? Не думаю что вы скажите что написать свой браузерный движок это простая задача.
А игры, конечно, бывают разные. Бывают и очень непростые алгоритмы, но они очень редки.

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

Конечно в плане математики они сильно уступают NWChem, но это не делает их простыми.
Давайте не ударяться в софистику. Движок игры — это не UI. UI — это то, во что тыкают кнопками и мышкой. Иногда еще gamepad туда же.

То, что я привел в пример то, что более-менее понимаю, не означает, что я не верю в существование других сложных программ.

Но, еще раз: UI среди них нет.

Я читал код Android Framework и изучал внутреннее устройство виджетов и всего с ними связанного. Это — простой код. Он полон нюансов и мелких решений и оптимизаций, которые делают его непростым в плане развития, но ничего фундаментально сложного там нет.

Я разбирался во фреймворке SWT и много внутри видел. В частности, сделал статическую сборку для встраивания в исполняемые файлы. И там тоже нет ничего сложного.

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

Ещё раз повторяю, браузеры.
Что касается браузеров, то там вся сложность — оптимизация.

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

Приведите мне пример игры AAA-класса (по вашему же определению), написанной на Хаскелле.

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

Когда я говорил о простых задачах, вы прекрасно поняли, что я имею в виду. Я имел в виду задачи, решаемые фреймворком типа Qt и игровыми движками типа Unity.

Я вообще уже не понимаю, о чем этот спор. Изначально я утверждал, что C++ плохо справляется с решением задач в той области, для которой он считается (своими же адептами!) наиболее пригодным.
Вы пытались мне доказать, что Хаскелль не менее удобен для этого. Так? Я не вижу, чтобы его кто-то для перечисленных целей использовал.

Нет, я про хаскелль вообще не говорил, я лишь указал вам что вы неправы, говоря что UI и игры это простые задачи.
С++ как раз создан для решения сложных задач по типу браузеров и игр.
Я имел в виду задачи, решаемые фреймворком типа Qt и игровыми движками типа Unity.
Дык и я говорю о том же, фреймворки типа Qt и дивижки типа юнити это не простые задачи.
Изначально я утверждал, что C++ плохо справляется с решением задач в той области, для которой он считается (своими же адептами!) наиболее пригодным.
Я именно это и оспариваю )).
Есть подозрение, что спорить бесполезно.
Главная проблема «холивара» между адептами C++ и теми, кто относится к нему пренебрежительно, на мой взгляд, состоит в том, что люди, освоившие технологию в совершенстве, потратившие, к тому же, на это много времени (или просто очарованные по молодости ее мощью), искренне считают, что другим, лентяям, достаточно лишь чуть-чуть поднапрячься — и они станут спецы и молодцы.

Я сам в институте почти что боготворил C++ за его красоту и целостность. Раздражение пришло позже, когда я сперва научился писать сложные (больше 5000 строк кода) программы, а потом увидел C# и осознал, сколько усилий в C++ приходится тратить лишь на то, чтобы программа не разваливалась на старте. При этом выигрыш по производительности, которым все адепты размахивают как флагом, составляет считанные проценты, а там, где он существеннее, есть JNI (в Java) и PInvoke (в C#). И программа, написанная на «коктейле» будет работать так же быстро. Только она будет надежнее. И вы ее быстрее сделаете.
UFO just landed and posted this here
>Если меня как плюсиста посадить за написание соответствующего C#-кода, я бы наверняка наделал там ошибок.

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

Проблема не в сложности C++! Я про сложность не писал ничего. Проблема в том, что он весь состоит из «дырявых» абстракций. Чтобы написать нормальный код на C++ надо сперва самому придумать и выбрать некое подмножество его возможностей, которым вы сами себя ограничите и запомнить набор правил. А потом железно этим правилам следовать. В противном случае у вас будет ошибка в месте кода А, а программа свалится через 10 минут в месте кода Б. И идите — разыскивайте, где вы там испортили что…
UFO just landed and posted this here
Если я правильно понял Липперта, то не поймал бы в два счёта с помощью стектрейсов и отладчика просто потому, что оно бы не падало, а просто тихо считало не так.

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

Но самое главное, что «считает не так» — почти всегда видно сразу, на первом тестировании. А ошибки с копированием объектов и вообще памятью — похуже.
UFO just landed and posted this here
Интересно узнать каков ваш опыт работы с С++? Просто за те 6 лет что я на нём работаю. у меня никогда небыло трудностей что вы говорите, даже когда только начал. Всегда выбирал методы нужные для решения задачи исходя из задачи, основная идея языка это е использовать того что ненужно, а по вашим словам получается какбудто есть всего 2 возможности, либо используй всё либо используй ничего. Оч странно выглядит.
Что-то я не видел ни программ C++ где нужно прикладывать массу усилий чтобы все «не развалилось при старте», ни программ на C# где не требовалось бы писать кучу еще более дурацкого boileplate. Весьма показательным, имхо, моментом является то что у нас в проекте когда такие же «светлые головы» решили что вычислительное ядро будет на плюсах, а бизнес-логика и UI — на шарпе, то первым (!) что было сделано на шарпе стало использование какого-то дурацкого IOC фреймворка, который спрятал половину инициализации в непрозрачный third-party бинарник. Затем чуть ли не полгода эти «спецы в C#» делали несложный интерфейс с одним окном для рендеринга 3d-сцены, одним меню и несколькими кнопками в этом окне, т.е. вещь настолько тривиальную, что дальше уже некуда. Дальше были танцы с бубном чтобы подключить к этому окну third-party рендерер. Дальше, естественно, возникли обширные проблемы в общении между плюсовым кодом и шарповым, так что несчастный message box пилили, наверное, месяц. Далее я заметил что добавление банальнейшего элемента в меню требует ручной правки то ли шести то ли восьми (!) файлов. Шаг влево, шаг вправо — и где-то отваливаются ресурсы, из-за чего message-box ы с сообщением об ошибке выглядят абсолютно пустыми. Как сделать банальное диалоговое окно — непонятно вообще, такое впечатление что нужно править вручную машиночитаемую разметку — привет XAML. Слава Богу, что пока что нам это не нужно и это создает со стороны впечатление что UI успешно сделан и прекрасно работает, но я-то знаю, что диалоговые окна которые раньше мог спокойно добавить любой разработчик, сейчас может добавлять только один или два человека в команде, которые шарповый код писали, потому как больше в этом коде сходу разобраться не может никто. В общем, пи**ец как он есть. А ведь могли бы сделать на Qt — там все а) работает с полпинка, б) легко читается и правится, в) не требует геморроя с взаимодействием между кодом на шарпе и плюсах. Pinvoke — это хорошо когда надо одну-две функции дергать, а когда на плюсах «живут» не отдельные «оракулы» которые C# дергает в синхронных вызовах а полноценные непрерывно обрабатывающие данные потоки асинхронно от C#, то пробросить (и отладить) нормальный интерфейс довольно непросто.

Это я конечно не к тому чтобы C# плох и виноват во всех этих бедах. Понятно что там программисты на шарповой стороне были очень посредственными и накосячили с архитектурой. Но, блин, вся ж идея с шарпом, по идее, в том что там накосячить должно быть сложно, а сделать правильное решение — легко и просто. И вот этой простоты я что-то абсолютно не наблюдаю. Примерно такую же хрень мог бы нагородить в UI-е любой школьник пишущий на плюсах для MFC. Вероятно шарп это шаг вперед по сравнению с MFC (ибо последний — это вообще запредельное убожество), но по сравнению с Qt, по ощущениям, это два шага назад.

Здесь правда следует сделать поправку на то что плюсовые программы я писал сам, тогда как шарповые смотрел сделанные другими.
первым (!) что было сделано на шарпе стало использование какого-то дурацкого IOC фреймворка, который спрятал половину инициализации в непрозрачный third-party бинарник.

Имя, сестра, имя!

(но вообще, конечно, плохая архитектура — она на любом языке плохая архитектура, от нее не защитишься)
Caliburn.Micro и какую-то хрень LogoFX, но по сути это совершенно неважно.
Моя позиция в том что с хорошей архитектурой и на плюсах и на шарпе будет написан примерно одинаковый код за примерно одинаковое время. У каждого языка будут свои плюшки и минусы (шарп — лучше стандартная библиотека, тогда как к плюсам надо еще подключать что-то, плюсы — быстро работают из коробки), но общая разница будет весьма незначительной. Поэтому когда человек говорит что на шарпе писать сильно проще то у меня возникает отчетливое ощущение что на плюсах он просто писать так и не научился.

Плюсы, имхо, не любят по двум основным причинам
1. Там много legacy-проектов с абсолютно убийственной реализацией тогда как на шарпе проекты в среднем новее. Отсутствие нужды возиться с MFC потому что проект начинали 15 лет назад и теперь без радикальной переделки MFC оттуда не вытравишь любому языку дает много очков вперед :D
2. Плюсы учить дольше и кривая обучения там круче, а ошибки в нем более красочны.

Второй пункт приводит к тому что многие школьники вначале набивают себе шишек в плюсах, и так и не сумев пробиться через этап первоначального обучения уходят в шарп, где учиться проще. Они там допускают те же ошибки что и в плюсах, но поскольку их последствия менее фатальны (особенно в мелких проектах) и обучение идет быстро, то возникает ощущение что эти ошибки связаны с личной неопытностью и вообще не критичны, тогда как в плюсах у них возникает ощущение что ошибки ты будешь совершать всегда и любая из них может убить программу. Начальный сложный период экстраполируется на весь период обучения плюсам, из этого делается вывод что плюсы — это сплошное сражение с языком, а первый пункт подкрепляет эту идею наблюдением «вон смотрите что специалисты наворотили».

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

… людьми с одинаковой компетенцией и желательно в вакууме.

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

Мне до сих пор интересно где-нибудь найти факты о том, сколько нужно времени, чтобы «научиться писать» на C++ и C# «на одном уровне».

Но вообще, из «плюсы учить дольше» неизбежно следует «на шарпе писать проще». Потому что иначе почему учить дольше? И весь ваш дальнейший пример это все и подтверждает.

Грубо говоря, я могу посадить джуниора писать код на C# для реального проекта. Он (код, не джуниор) будет некрасивым, неэффективным, но он будет работать, и если будет ронять систему, то это будет видно сравнительно легко. Я совершенно не уверен, что все то же самое можно сказать о C++.
UFO just landed and posted this here
(как обычно, метафора больше говорит о желаниях сказавшего, нежели о реальном положении дел).

Во-первых, все зависит от определения «легче». Почему-то не все, кто могут копать лопатой, могут пользоваться бульдозером.
Но во-вторых, даже если принять под «легче» — «производительнее», то как легче выкопать ямку на штык на однодневной палаточной стоянке — лопатой или бульдозером?

(ну и вообще, бульдозером ямы не копают)
UFO just landed and posted this here
Но вообще, из «плюсы учить дольше» неизбежно следует «на шарпе писать проще». Потому что иначе почему учить дольше? И весь ваш дальнейший пример это все и подтверждает.


Я пытался показать что более длинное обучение в конце может давать и большую награду (пример с иероглифами). Отдельные буквы учить сложнее чем отдельные иероглифы, но выучив их все скачком оказываешься на плато колоссальных возможностей где можно реализовывать сколь угодно сложные тексты не заучивая новых иероглифов. В терминах «кривой обучения», у алфавита она вначале крутая, а затем практически плоская, тогда как у иероглифов она вроде как пологая, но подъем на ней длится неограниченно долго, а у живых людей еще и тупо упирается в конечную емкость памяти. Выше так же приводили прекрасный пример с бульдозером.

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

Джуниоры у нас рутинно пишут код и для C++ проекта. Естественно это требует определенного присмотра. Но если объяснить джуниорам несколько простых техник и давать вовремя по рукам при попытке писать свои велосипеды, то у них код будет работать и не будет ронять систему, точно так же как и в шарпе. Я верю что в шарпе без подобного присмотра за джуниорами программа будет падать куда реже чем в плюсах, но, простите, не верю что написанный таким образом код будет легче дебажить или мэйнтэйнить. Будут спагетти с кучей дубликатов и странной логикой и то что оно будет не крэшиться а «просто» выдавать неверные ответы в неожиданных местах, переставать работать при малейших правках и требовать переписывания 90% кода для добавления небольшой фичи окажется слабым утешением.
Я пытался показать что более длинное обучение в конце может давать и большую награду (пример с иероглифами).

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

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

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


Сложнее, уважаемый. На начальном этапе — сложнее. Потому и придуман он был НАМНОГО позже и потому иероглифическое письмо продолжает применяться в ряде стран, а в ряде языков алфавитная запись имеет значительное сходство с иероглифической (не зная слова невозможно расшифровать его запись). В реальных языках вдобавок куча проблем с исторически обусловленными исключениями, связанными с тем что устный и письменный языки эволюционируют параллельно и не совсем идентично. Иероглифическое письмо «учится» в понимании «написать примитивнейшее сообщение» значительно быстрее.

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


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

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


Пример неудачный.

Для того, чтобы выучить C++ и C#, необходимо узнать примерно одинаковое количество примерно равно сложных вещей. В C++ будет небольшой перекос в сторону управления памятью и низкоуровневых понтий, в C# будет страшное слово «рефлексия» и мозгодробительный P/Invoke с нитрыми аннотациями. Везде — свои заморочки.

Я говорю это как человек, который примерно в равной степени владеет обоими языками. Правда-правда. Что бы обо мне тут не говорили за мою позицию выше, я вполне неплохо способен писать и на «крестах».

И именно потому, что я на них пишу, могу сравнивать.

В C++ часто возникает ситуация, когда мелкая ошибка (даже не проектирования, а кодирования) заставляет вас потом сидеть над кодом с микроскопом. Я один пример выше приводил, он не единственный даже в моей небольшой практике. Именно эта особенность языка делает его неудобным.

Мне приходилось ловить странный NullPointerException в Java Enterprise проекте на 1000 с лишним классов. Это было тяжко. Там, кстати, было IoC, которое я сам терпеть ненавижу, но без которого в таком громадном проекте — никуда. И могу сказать, что это было нелегко.

Но поймать мелкую багу в C++ коде подчастую — просто кошмарно трудно.

И если вы не экстрасенс, то никакие знания и квалификация всм не поможет. Ошибки C++ не прощает.
У нас проект на сотни тысяч строк кода и мне доводилось искать в нем кошмарно сложные ошибки. Да, в плюсах это определенный дзэн, да это может требовать знания ассемблера и прочтения манов по x86. Но нет, это вполне реализуемо и значительно проще чем, к примеру, искать ошибки в плохо написанной многопоточной логике. Дебаггер и логгирование способны творить чудеса, самые мегасложные ошибки при понимании того что и как ты делаешь отлаживаются за один-три дня (один кстати раз нашел баг в компиляторе :D — там, впрочем, все было довольно просто, хотя человек не способный проанализировать дизассемблированный код там бы удавился). Да, у меня ушло 15 лет на то чтобы этому научиться. Но, ёклмн, многопоточные баги (которые вообще не зависят от того, шарп это или плюсы) могут ловиться месяцами (их тупо бывает чудовищно сложно воспроизвести), а еще у нас в проекте есть математические/инженерные проблемы которые решаются ГОДАМИ с довольно незначительным прогрессом несмотря на квалификацию занятых в этом решении людей. Вот это я понимаю — сложность. А самые сложные ошибки характерные чисто для плюсов — это так, рутина на несколько дней, достаточно просто понимать куда надо смотреть и методично проверять что там все «как надо». Примерно как старый телевизор ремонтировать, если Вы еще застали то время когда они из дискретных компонентов набирались :)

Но ладно, это хвастовство и лирика :). С практической точки зрения куда важнее то что по моему опыту отлова подобных проблем, реально это проблема для считанных процентов от общего объема кода. Подавляющее большинство плюсового кода при минимальной самодисциплине пишется так что подобных проблем там не возникнет практически никогда у самого распоследнего джуниора. Главное по рукам надавать вовремя, чтобы отбить идиотские практики изобретения велосипедов и заставить людей пользоваться стандартными (и что, блин, характерно — удобными) вещами. У нас же ведь как бывает? Смотрит человек на задание и вместо того чтобы покопаться в библиотеке или хотя бы спросить старших берет и пишет свой самоходный веник на паровой тяге. В суровом C-style или напротив с кучей плюсовых наворотов а-ля Александреску. И естественно в половине случаев недооценивает сложность задачи. Но стоит начать использовать, блин, банальнейший STL и оказывается что, во-первых, задача в подавляющем большинстве случаев прекрасно решается штатными средствами этой или другой уже имеющейся библиотеки, а во-вторых получившееся решение работает с первого раза, ничего не крэшит, и — сюрприз — еще и делает это зачастую быстрее чем самопальный код :). Да, есть 1-5% кода где нужен хардкор и требуется определенный опыт. Да, это нередко ключевые компоненты на которых держится половина программы. Но, я Вас уверяю, неважно плюсы или шарп — если Вы на эти компоненты посадите джуниоров, то неизбежно огребете проблем по полной программе.
Для людей вашего уровня язык программирования уже значения не имеет. Речь идет о начинающих и о тех, кто в отрасли 2-3 года.

Я сам, увы, ассемблер не знаю. Но как функции вызываются, знаю более менее, даже ffi, например, щупал. Но ковыряться в этом всём, когда в голове usability — сущий ад.
Гоните ваших «спецов» взашей. Не за то, что он используют С# (он отличен), а за то, что они его использовать не умеют.

UI любой сложности на Windows Forms делается так быстро и легко, что даже сравнивать не с чем. Я в институте на нем запилил программу мат моделирования со сменными счетными модулями, плагинами и чертовой тучей настроек. При этом счетный код был написан на C++/CLR. И всё это прекрасно связывалось между собой.

А если вы под Mono пишете, то P/Invoke — довольно простая технология. Сложнее, чем JNI, но я не знаю, кем надо быть, чтобы ее не освоить на базовом уровне за неделю.
Там WPF а не Windows Forms. Типа круче и вообще в духе великих идей Микрософта отдадим UI на аутсорс дизайнерам. Ибо великий WPF отделяет presentation от model, так что наши программисты забабахают model, а дальше WPF ее магическим образом привяжет к UI. Я был сильно против, но именно идея с аутсорсом, насколько я понимаю, в итоге «продала» C# менеджменту. Надо ли упоминать о том что на практике эта идея через полгода благополучно отправилась на свалку?

P/invoke нормально работает когда код можно свести к некой функции «возьми A и Б, посчитай В(А, Б) и верни результат». И то будет совершенно непонятно нафига нужный геморрой (мы же вроде как себе жизнь упростить хотим, а не усложнять на ровном месте?). А у нас код тянет от драйвера в реальном масштабе времени данные с железа и эти данные тут же в реальном времени на десятках потоков и в сотни шагов обрабатывает. И наладить взаимодействие между этим самоуправляющимся кодом самостоятельно генерирующим события и UI через p/invoke, внезапно, оказывается не тривиально.

А так я же сразу написал что проблема не в шарпе, а в программистах. Просто мне регулярно пытаются втюхать что шарп де позволяет получать хорошие результаты с посредственными программистами. А по моей практике — нефига подобного. Крэшиться программа может и будет реже, но мэйнтейнить и дебажить ее будет ровно таким же геморроем.
Ибо великий WPF отделяет presentation от model, так что наши программисты забабахают model, а дальше WPF ее магическим образом привяжет к UI. Я был сильно против, но именно идея с аутсорсом, насколько я понимаю, в итоге «продала» C# менеджменту.


Архитектуру MVC придумали не в Microsoft. Ей более 40 лет. И то, что современные UI-фреймворки подталкивают к ее использованию — однозначно хорошо. Я насмотрелся на программы, в которых View и Controller перемешаны друг с другом. И как юзер, и как разработчик.

Ваша неправота в этом вопросе, однако, не отмняет того факта, что MVC должно быть не только в WPF, но и в голове разработчиков (как и ООП и много других умных вещей). В противном случае норального решения не получится.
Я вовсе не против MVC. Просто там уже не выходит того «легко и просто» о котором Вы пишете и грамотная реализация требует достаточно высокой квалификации и значительной работы и это обесценивает преимущества шарпа — и выигрыш получается (в относительных цифрах) невелик, и джуниора туда уже не поставить. Кроме того этот пример хорошо показывает что на бумаге микрософтовские технологии типа WPF очень удобны и позволяют делать крутые вещи, а как доходит до реализации — половина обещанного не срастается, а вторая половина неудобна.
Кроме того этот пример хорошо показывает что на бумаге микрософтовские технологии типа WPF очень удобны и позволяют делать крутые вещи, а как доходит до реализации — половина обещанного не срастается, а вторая половина неудобна.

К счастью, это относится не ко всем технологиям MS.
Я ничего про «легко и просто» не писал. MVC — это не просто. Но это — чуть ли не единственный подход, который позволяет поддержиывать крупные проекты со сложным интерфейсом.
Справедливости ради, не единственный. Шаблонов отделения логики от представления больше одного, и для разных типов приложения лучше подходят разные из них.
Вы правы. Я говорю об MVC как о самой идее отделения логики от представления. То есть сам факт, что такое отделение в серьезном проекте необходимо, сомнений не вызывает.
Эти проблемы (если они есть) тривиально профайлером вылавливаются и устраняются в солидных размеров проекте где работают десятки программистов за пару часов работы одного человека
На моей практике из 10 программистов профайлером умели пользоваться в среднем 4, меньше половины.
ИМХО на команду из 20 человек за глаза хватит и одного умеющего пользоваться профайлером :)
Но проверить не могу, поскольку в моей компании профайлер худо-бедно умели использовать все
UFO just landed and posted this here
> Поэтому vector использует динамическую память для хранения массива и должен честно проверять выход за границы.
В релизе vector[] НЕ проверяет выход за границы. Если хочется «честногО» сравнения, используйте vector.at()

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

Типовой код. Бабл сорт. Типовой. Большая вероятность… Какой смысл сравнивать производительность типовых лабораторных работ первокурсников?
Замените бабл сорт на свертку. По большому счету ничего не изменится.

В релизе vector[] НЕ проверяет выход за границы.

Однако…
> Те кто знают (или думают что знают) C++
Классно вы себя приложили.) Различие между [] и at именно в том, что проверка выхода за границы в релизе есть только у метода at. Встречал кривые реализации, где скобки даже в дебаге границы не проверяли. Именно поэтому между массивом и vector в релизе разница околонулевая (на усмотрение компилятора).
Я не сравнивал детали (мне они не интересны), я сравнивал код, который может написать человек. При прочих равных 9 из 10 напишут [], а не at. То что [] позволяет отстрелить себе ноги — это прекрасно.
Вот и я о том же! Сперва один сравнивает языки неадекватным способом. Затем другой, пытается доказать неправоту первого. При этом оба не знают тонкостей «противного» им языка.
Допустим, что сравниваем производительность пузырька, мне не жалко. Но! Программу на С++ должен писать хорошо разбирающийся в С++ программист, а на C# — разбирающийся в C#. Без обид, но С++ вы если и знаете, то не сильно плотно. А я не смогу написать максимально эффективно на C#, только если случайно совпадёт. Т.е. все эти три статьи о «сравнении» языков — пердёж в лужу (извините, не ругайте).

C-style нужно делать через указатели. Почти 100% гарантия того, что будет самый эффективный вариант. Если компилятор индексированный доступ сам не смог в указатели переделать.
Сделайте форк, улучшите код. Вам кто мешает?
Вы же хорошо разбираетесь в C++?

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

Или, внезапно, любой процессинг где важнен лэтенси и/или трупут. Те же трейдинговые системы, сетевые фс, вебсервера, всё что безкровно плохо масштабируется горизонтально.
Перефразируя, трупут это тупо деньги.
А вот лэтенси это искусство.
Правильно все, но C++ и вообще скорость кода не при чем в большинстве случаев.
Графика давно делается на видеокартах и руками никто пишет текстурирование. Физика в играх — векторные вычисления, для них есть SIMD в .NET 4.6 (в этом сравнении нет).
Сетевые фс и прочие серверы упираются в IO, поэтому им скорость кода до одного места.
Трейдинговые системы, кроме HFT, не требуют реакции в 10мс. Ордер от обычного терминала исполняется минутами,10мс ничего не решат.
По большому счёту — согласен.

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

Либо, как указал товаришь ниже — системы, которые в принципе сами по себе производительны на грани того, что в них хотят пропихнуть за единицу времени.
Тобишь, если есть риск просто не уместиться на заданной платформе, то тоже разумно выбрать инструмент, который максимально приближает вас к этой цели.
Хотя если речь не идёт о размере (физическом железки), обычно такая экономия тоже на спичках.

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

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

Из областей где ещё может понадобиться быстрый код это например парсера — что бы упереться в i/o надо всё таки сначала успеть всё разгрести и подготовить в нужном формате, а так же дать время выполниться полезной нагрузке. И криптография, хотя там обычно всё таки C а не кресты, да и многие вещи наверное тоже можно порешать аппаратно.
Однако, многие готовы перестраховаться и переплатить (сейчас их всё меньше). Ибо, если ты не можешь масштабироваться вширь, то экономить на вертикальном масштабировании как минимум глупо, зато делать это железом чаще дешевле.
Это вы о чем? Все масштабируемые системы вовсе не на C++ написаны, да и как связаны 10мс и масштабируемость?

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

Ну и больше субьективное мнение — при должном размере и скорости кода, а так же при грамотном ручном управлении памятью, таки общий прогресс системы всё таки будет выше за заданный квант времени (просто не всегда бывает нужен выше).
А кто спорит? Только это вы не про C++ пишите. Он, к сожалению, делает довольно много работы (подсчет ссылок, вызов деструкторов, выделение\освобождение памяти). Это на голом C или C_с_классами можно все контролировать, но и вероятность ошибиться на голом C в разы выше.
О_О. Подсчёт ссылок в c++? Походу, я чего то не знаю…

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

>да и как связаны 10мс и масштабируемость

Вот стоит у вас задача, за 100 мс обработать 10 запросов. А потом появилась задача обработать 1000 запросов. За 10 мс каждый. Потом ещё, потом ваша железяка за 3ккк не потянула. На ipc при горизонтальном масштабировании — тратиться 10мс. Вы уже не можете утверждать что можете масштабироваться горизонтально бескровно. Если речь идёт о любом маломальском реалтайме (что то нету в CS 500 на 500 баталий, хотя казалось бы мультикаст всех спасёт), то вы в принципе не можете масштабироваться горизонтально ибо на ipc у вас уходит больше времени, чем нужно на обработку запроса (надо же ещё пэйлоад уместить).

Выход — масштабироваться вертикально. Покупать 10G сетевухи, крутую мать, кидать на неё процов, памяти и производить ipc за более короткое время, так как оно перестаёт быть собственно ipc, а становиться чтением записью памяти. А так же утилизировать это всё максимально экономно.

P.S. CS — чисто первое что в голову пришло, но факт что в тех же сетевых игрушках не просто так мир разбит на зоны, а комнаты имеют вместимость.
О_О. Подсчёт ссылок в c++? Походу, я чего то не знаю…

Смартпоинтерами не пользуетесь?

Нет, ну есть конечно всякие умные указатели, однако без них кресты не прям таки сразу превращаются в C_с_чем бы то ни было.
Именно сразу и превращаются. По большому счету в чем разница между new\delete и malloc\free, если каждый руками выписывать?

Вот стоит у вас задача, за 100 мс обработать 10 запросов.

Когда запрос приходит по сети, то большая часть времени тратится на сетевой IO. Очевидно что в этом случае надо не ждать пока весь запрос будет получен, а начинать обрабатывать пока клиент шлет байты. Например в RavenDB (NoSQL база на .NET) чуваки сделали так, что умудряются писать на диск пока клиент отправляет данные.

Когда сможете повторить такое на плюсах — приходите поговорить о массовой обработке запросов.
Смартпоинтерами не пользуетесь?

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

Именно сразу и превращаются. По большому счету в чем разница между new\delete и malloc\free, если каждый руками выписывать?
— Ни во что не превращается. Отсутствие new/delete никак не связано с умными указателями. Я вот пишу код без new и без умных указателей. Да и по большей части без указателей вообще.

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

unique_ptr нельзя передать просто в метод. А если метод может сделать что угодно, то ничего кроме shared_ptr вообще передавать нельзя.

Я вот пишу код без new и без умных указателей. Да и по большей части без указателей вообще.

Искренне рад, что у вас такие простые задачи.
> unique_ptr нельзя передать просто в метод.
можно передать по ссылке
unique_ptr нельзя передать просто в метод. А если метод может сделать что угодно, то ничего кроме shared_ptr вообще передавать нельзя.

— остановитесь пожалуйста писать бред.

unique_ptr можно передавать в метод. Это будет означать передачу владения. Если же владение передавать не надо, то передаётся обычный указатель с помощью p.get(). Также можно передать ссылку на объект.

Если же ваш метод делает вообще все что угодно, то я даже не знаю как это комментировать. Тут вам ничего не поможет. Даже C#.

Искренне рад, что у вас такие простые задачи.

Объекты хранятся в контейнерах, доступ осуществляется по итераторам. Стандартная библиотека все делает за меня. И от сложности задачи это слабо зависит. Конечно есть случаи, когда нужны new, указатели и умные указатели, но это совсем не основной стиль использования современного C++. new при этом обычно размещается в конструкторе некоего класса, delete в десрукторе, и дальше работает RAII.
Когда запрос приходит по сети, то большая часть времени тратится на сетевой IO. Очевидно что в этом случае надо не ждать пока весь запрос будет получен, а начинать обрабатывать пока клиент шлет байты. Например в RavenDB (NoSQL база на .NET) чуваки сделали так, что умудряются писать на диск пока клиент отправляет данные.

Когда сможете повторить такое на плюсах — приходите поговорить о массовой обработке запросов.
— У тех кто этим занимается никаких проблем нет. Вы например про boost.ASIO что-нибудь слышали?
Не только слышал, но и видел, поэтому и говорю — приходите как сможете повторить.
Именно сразу и превращаются. По большому счету в чем разница между new\delete и malloc\free, если каждый руками выписывать?

То есть для вас С++ это исключительно использование умных указателей? Шаблоны, RAII, ООП, оказывается это всё ерунда, о чём я думал ((. Я например когда писал свой парсер умные указатели не использовал, я вообще писал свой аллокатор, который освобождал потом всю память махом когда он переставала быть нужной. Чем дальше вы пишите тем яснее становится что навыки использования С++ у вас совсем скудные.
Интересно, как вы собрались RAII делать без умных указателей?
ООП — это реально ерунда, stl вообще без ООП сделан и выглядит гораздо лучше, чем если бы его сделали на ООП.
Шаблоны — хорошая штука для библиотечного кода, но для прикладных задач вполне можно без них обойтись.
XDDD Пожалуй в данном случае даже отвечать ненужно ибо вы сами себе могилу выкопали, но всё таки отвечу.
RAII работает не благодаря умным указателям, это умные указатели работают благодаря RAII. RAII связан с вызовом деструктора.
Например при удалении такого класса
class Abc
{
  string A;
  map<string, vector<string>> B
  tuple<string, vector<string>> C
}

У всех его членов вызовется деструктор без какого либо явного вмешательства пользователя.
ООП — это реально ерунда, stl вообще без ООП сделан и выглядит гораздо лучше, чем если бы его сделали на ООП.

Это как бы неправда любой контейнер в stl имеет определённую иерархию (как минимум в реализации от MS)
Шаблоны — хорошая штука для библиотечного кода, но для прикладных задач вполне можно без них обойтись.

Да но тогда придётся отказаться от stl или использование шаблонов и их написание это взаимоисключающие вещи? И опять же, да для проектов Hello world они и правда ненужны, но вот в реальности всё не так радужно.
ОК, вот у вас есть A. И вы хотите A передать в функцию, которая может делать что угодно, вплоть до того, что сохранить A в глобальной переменной. Привет умные указатели ;)

То что вы можете в подмножестве кода обойтись без умных указателей не означает, что можно писать идиоматичный C++ код вообще без них.

Это как бы неправда любой контейнер в stl имеет определённую иерархию (как минимум в реализации от MS)
Это детали реализации, сравни с контейнерной библиотекой C#\Java, там из всех ушей ООП торчит/

Да но тогда придётся отказаться от stl или использование шаблонов и их написание это взаимоисключающие вещи? И опять же, да для проектов Hello world они и правда ненужны, но вот в реальности всё не так радужно.
В реальности прикладной код (который решает бизнес-задачу) почти не требует шаблонов. Прикладной код конкретный, а не обобщенный.

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

Не спорю при этом, что для библиотечного кода прекрасно подходят шаблоны и именно из за шаблонов stl крут.
ОК, вот у вас есть A. И вы хотите A передать в функцию, которая может делать что угодно, вплоть до того, что сохранить A в глобальной переменной. Привет умные указатели ;)

То что вы можете в подмножестве кода обойтись без умных указателей не означает, что можно писать идиоматичный C++ код вообще без них.

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

Да )) и эта деталь означает что stl использует ООП
В реальности прикладной код (который решает бизнес-задачу) почти не требует шаблонов. Прикладной код конкретный, а не обобщенный.

Что значит почти? То что вы не писали шаблоны не значит, что почти не требует, это всего лишь значит что у вас мало опыта, либо область ваших задач не требует использование шаблонов. У меня например ещё не было ни одного проекта где бы я не писал шаблоны.
У меня например ещё не было ни одного проекта где бы я не писал шаблоны.

Когда в руках молоток все кажется гвоздями.
Попробуйте другие языки, Go например. Поймете, что и без написания шаблонов можно прожить.
UFO just landed and posted this here
Разница — в RAII, которое не строго равно умным указателям. Умные указатели это ширпотреб для случаев когда важнее внятно записать бизнес. Однако, есть ещё размещение например, где RAII также остаётся в силе.
Не просто так эту концепцию таки стали потихоньку пилить и в .net и в java, посредством всяких with и lock.

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

> Когда запрос приходит по сети, то большая часть времени тратится на сетевой IO.

Зависит исключительно от типа полезной нагрузки. Выполнять i/o одновременно с обработкой данных это квинтэссенция современного серверного ПО. Так делают хоть на эрланге хоть на плюсах, никакого рокетсайнс там нет.
Это в эрланге нет, а в плюсах — еще какой. Даже нагуглить такой код на плюсах проблематично.

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

Например в случае визуального редактора с undo-redo и нетривиальными объектами это уже крайне сложно сделать. Я сам такое писал примерно в 2006 году, и не зная буста и начитавшись александреску я изобретал свои smart_ptr для этой задачи.
Сложные задачи — надо декомпозировать. А над архитектурой — задумываться. Подсчёт ссылок был сделан для того, что бы сократить трудозатраты на эти задачи, особенно в контексте потоков. Для этого же он служит и в плюсах, однако, тут никто не заставляет использовать его онли.
UFO just landed and posted this here
Так вы же читерите там! Ищете словоформы по хэшам бинарным поиском, а надо строго линейным! Дважды, чтобы наверняка! Иначе не честно.
Если вы теряете ВСЮ производительность из-за подсчёта ссылок, то вы явно делаете что-то не так. Самый простой вариант — сделать интрузивный подсчёт ссылок, тогда он получается практически бесплатный, потому что счётчик находится в объекте, а не хранится где-то отдельно и нет лишней беготни по памяти — минимум кэш миссов.
Ничего личного, но в 2006 году знаний С++ у вас было меньше, чем сейчас, поэтому что вы там натворили — одному Богу известно. А говнокод может тормозить по любому поводу.
Очень забавно слышать таки голословные утверждения в сторону геймдева, графика — да делается на видеокарте, только вот организация ресурсов, и объектов на вывод и многое другое делается не на видюхе. Октри, ии, частицы, батчинг, анимация (вы даже не представляете как сильно нужно извращаться чтобы вывести с хорошим фпс хотя бы 150 моделей). Да и в физике кроме векторных вычислений используется огромное количество алгоритмических оптимизаций. И это мы ещё не дошли до мобильных платформ. Так что попрошу не делать голословные заявления в теме в которой не разбираетесь, или вы думаете что в игровых компаниях работают идиоты которые используют С++ чисто из принципа?
Тем не менее огромное количество игр делается на Unity, который, внимание, C#. Так что непонятно что вы пытаетесь сказать. Исходный посыл был в том, что ради 10мс стоит заниматься C++, я лишь сказал что в играх не часто встречается эта проблема.

Самое смешное, что для высокоуровневой логики в играх используются скриптовые языки, которые иногда тормозят дико. Почему бы их не заменить на C++? Оказывается C++ слишком сложен для этих задач. Или вы думаете в игровых компаниях работают идиоты?
Тем не менее огромное количество игр делается на Unity, который, внимание, C#

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

Именно что для игровой логики которая является наименьшей проблемой для производительности, ваш кэп. Ну и да, чаще всего стараются выбрать наиболее быстрые скриптовые языки, lua, AS, JS/
Который, внимание, С++. С# используется лишь для скриптования игровой логики, упс.

Как же люди целые игры пишут только на C#, они наверное не знают что там надо C++ использовать.

Именно что для игровой логики которая является наименьшей проблемой для производительности, ваш кэп
Она является наибольшей. Помню игру СТАЛКЕР, у которой логика на Lua. Бегаешь по полям — 30+ fps, появляются 3-4 противника (не в кадре, а просто в окружении) — 12 fps. Это ты называешь наименьшей проблемой? Или цивилизация, в которой противники ходят минутами это меньшая проблема?
Как же люди целые игры пишут только на C#, они наверное не знают что там надо C++ использовать.

Я говорил про сам движок, который написан на С++, а не про пользователей этого движка. Повторюсь игровая логика зачастую является наименьшей проблемой для производительности.
Она является наибольшей. Помню игру СТАЛКЕР, у которой логика на Lua. Бегаешь по полям — 30+ fps, появляются 3-4 противника (не в кадре, а просто в окружении) — 12 fps. Это ты называешь наименьшей проблемой?
Да это наименьшая проблема, я не знаю как устроен движок для сталкера, но склонен думать что это проблема не скриптового языка а организации архитектуры в целом.
Я говорил про сам движок, который написан на С++, а не про пользователей этого движка.

Да хоть на ассемблере, без разницы.
А пользователи движка не программируют графику и физику на C#? Или они там магически сами считаются?

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

В тупых коридорных шутерах поведение врагов примитивное и там скрипты действительно не проблема. А в игрушках типа цивилизации, где вся логика на python, скорость скриптов — основная проблема. Тем не менее на C++ не переписывают что-то.
А пользователи движка не программируют графику и физику на C#? Или они там магически сами считаются?


Графику и физику — нет. Пользователи лишь отдают движку граф сцены, а тот, написанный на С++, отрисовывает все как надо. Физический движок тоже на С++ написан. То, что в C# проброшены интерфейсы к физике, ничего не меняет.
Ага, граф сцены из воздуха получается. Ну мы уже поняли, что создатели игр на Unity вообще ничего не длают, за что им только деньги платят…
Один объект графа сцены может быть моделью на десять тысяч полигонов. C# работает с одним объектом, С++ с буфером на несколько тысяч вершин. С физикой все еще круче.
Создателям игр на Юнити платят за создание игр, а не за работу над движком.
А пользователи движка не программируют графику и физику на C#?

Нет.
они там магически сами считаются?

Да, хоть и не магически.
В сталкере проблема была именно в скриптовой логике, там десятки тысяч строк, поведение персонажей заскриптовано, поэтому при нескольких персонажах на сцене все тормозит.
Вы перед профайлером свечку держали? Откуда такая уверенность?
С саппортом общался. Я как раз думал что тормозит из-за графики. Понижал настройки — все равно тормозит. Потом спросил что за фигня, говорят процессор слабый и не справляется с AI. Потом выяснил что весь этот AI сделан скриптами в Lua.
Ai крайне обширен. Если делать на скриптах только поведенческие алгоритмы то ничего тормозить не должно. А если писать всю систему ии вместе с поиском пути, машиной состояний, или что они использовали. То не стоит удивляться, что всё тормозит ибо эту часть и выносят на С++.
Кстати ещё дополню.
Самое смешное, что для высокоуровневой логики в играх используются скриптовые языки, которые иногда тормозят дико. Почему бы их не заменить на C++? Оказывается C++ слишком сложен для этих задач.

Расскажите это пожалуйста людям которые используют Unreal engine для разработок AAA игр. По видимому они зря используют С++ в качестве основного языка для кодирования игровой логики.
Может и не зря, я не знаю всех обстоятельств. Но есть куча игр со скриптами (Lua, Python) ты считаешь что они зря это делают и надо все на C++ переписать?
Хм… А мы тут пытаемся на несколько десятков микросекунд выиграть… Да, это HFT.
Система распознавания человека на путях в метро. За 100ms на дохлом cortex-a8 надо кучу аналитики провести. А ведь еще приходит куча данных от других датчиков.
Для ваших задач, небось, и С++ покажется слишком медленным, и будете писать на чистом С :)
На данный момент все устраивает. Даже есть большой запас по производительности. Код, который отъедал 100% процессорного времени, теперь редко достигает 0,1% на тех же задачах)
Скажите, почему в примерах для C# нет «прогрева» JIT?
Есть, смотрите исходник на github.
Кстати, если уж вы за идиоматичность, то в коде на C++ стоит использовать std::swap(m[i], m[j])
к сожалению, речь о идиоматичности не идёт — пузырьковую сортировку, написанную ручками, кто использует?
Не путай идиоматичность кода и типичность задачи. Задачи разные, а код — почти одинаковый. В этом и есть идиоматичность. Обработки массивов сведутся в выделению памяти, циклам, получению и записи элементов по индексу.
Хотел и так написать, но аналога для C#, даже близкого, нету.
Сделал swap и однозначно скажу — не надо его использовать. В дебаге тормозит так, что работать невозможно.
Тогда и итераторы в stl на помойку! В дебаге тормозят так, что аж мама не горюй ;)
UFO just landed and posted this here
Кстати вопрос: а корректно ли использовать измерение времени выполнения тем же языком который мы поставили под микроскоп? Может все же внешнюю утилиту для этого использовать? И одну на оба теста
Во-первых, напомнило python, где тут же налетят и предложат десять способов написать правильный for, да еще и для разных версий.

По статье:
  • Все таки типовой код скорее всего работает с полями объектов или, по крайней мере, структур, аллоцирует большое количество новых объектов, частенько обращается к уже выгруженным страницам памяти и так далее. Так что навряд ли вы встретите сортировку чисел пузырьком в большинстве программ.
  • Это хорошо, что Вы тестируете на одних и тех же данных, но в чем смысл сортировать уже отсортированный массив?
  • Да и вообще, производительность числодробильного кода и там и там должна быть примерно одинаковая, основной источних тормозов — неучтенная работа с чем-то медленным, потом работа с памятью, и с большим отставанием идет кривая архитектура.
  • В программах C++ все же довольно часто прибегают к тем или иным способам оптимизации. И там и там сначала профилирование, анализ данных, а потом оптимизация.
Тут сортировка меняется на обратную, так что циклы кружатся не в холостую. С точки зрения пузырька — как раз самый плохой случай. Хотя, для него любой случай — самый плохой.
А какой JIT использовался? В 4.6 по дефолту ryujit уже стоит?
Можете попробовать прогнать тесты с другим старым\новым JIT?
В большом приложении такой оверхед сожрет весь выигрыш от использования C++.

Маловероятно. В каждом проекте узким горлышком будет своё место, и без профилирования делать такие выводы не стоит. Забыли поставить амперсанд — профайлер вам подскажет. Соглашусь всё же, что это ближе к коду на C#. Но на мой взгляд обе статьи занимаются странным. В любом случае сравнивается две конкретные реализации языков, имеющие нечто общее, но в целом принципиально по-разному устроенные. Что, если взять другую платформу? Другой компилятор и набор опций? Заглянуть наконец-то в профайлер?
В каждом проекте узким горлышком будет своё место, и без профилирования делать такие выводы не стоит.

Обычно узкое место не в коде, а в алгоритме или периферийных устройствах. Поэтому горлышки будут как на C#, так и на C++.
UFO just landed and posted this here
Скажите, а Вы убедились, что во всех примерах процессор работает на одинаковой частоте?
Я запускал две программы одновременно порядка 20 раз.
В обеих статьях, мне кажется, упускают как минимум garbage collection. Даже если весь ассемблерный код, кроме деаллокации, будет идентичным, C# будет медленнее (тестов у меня, конечно, нет, и все зависит от «паттернов» аллокации-деаллокации, но тем не менее). Кроме того, задержки будут происходить в непредсказуемое время.
Даже если весь ассемблерный код, кроме деаллокации, будет идентичным, C# будет медленнее (тестов у меня, конечно, нет, и все зависит от «паттернов» аллокации-деаллокации, но тем не менее).

Вот именно, что все зависит от паттернов. Представьте себе, что у вас веб-сервер, и освобождение ресурсов происходит уже после того, как данные возвращены клиенту — это освобождение влияет на производительность?
На ответ конкретно этому клиенту может и не повлияет. А вот следующему, на ответ которому уже не хватит памяти и придется делать GC и отдуваться сразу за всех — очень даже может быть.
И я реально с таким сталкивался, приходилось оптимизировать аллокации и ковырять настройки GC.
Ситуаций «не хватило памяти — решили сделать GC», конечно, лучше избегать.

Я не говорю, что управляемая память не несет издержек, просто иногда эти издержки можно разумным образом вынести за пределы пользовательской проблемы.
Для плюсов тоже есть сборщики мусора, если хочется.
Но C# может быть и быстрее, все зависит от конкретного кода, т.к. выделение малого объекта на куче по скорости идентично выделению объекта на стеке, в языках без сборки мусора куча устроена по другому и выделение занимает больше времени.
Хоть я и не сторонник C++ в сложных программах, но вынужден признать, что работа с памятью — слабое место мусоросборных языков. И в первую очередь, сложность в том, что GC почти неуправляем и труднопредсказуем.
Еще раз перечитайте. В C# выделение объекта на куче проще и быстрее, что делает его в определенных задачах быстрее. Но конкретно судить о языке по паре синтетических тестов все равно несостоятельно.
А в плюсах можно написать линейный аллокатор, и аллокация и сборка будет раз в 10 быстрее чем на куче.
И пишут.
Если обратишь внимание, то код тестов выполняется 100 раз, выделяя в каждом 40000 байт (+оверхед), это выше границы поколения, поэтому затраты на сборку мусора включены в измерения.
За счет того, что GC убирает мусор большими объемами, он гораздо эффективнее чем одиночные деаллокации в C++.
Например, если прогнать просто цикл с new\delete в C++, то он окажется гораздо медленнее цикла с new в C#.
Честно говоря, в первый раз слышу такую идею. Даже в Рихтере (CLR via C# который) про такое не пишут, кажется. Я не совсем понимаю, почему GC будет быстрее, чем С++ деаллокация, если собирает большими объемами. Вот почему будет медленее легко можно сказать: нужно остановить рабочий поток, запустить GC, протрекать, на какие объекты есть ссылки из стека (пройти весь стек, дерево объектов), записать адреса объектов в очередь freachable, и т.п. Я согласен, что если делать GC редко и удалять много, то вроде бы будет быстрее, чем если делать GC часто и удалять мало. Но это все равно будет медленнее, чем детерминистическая деаллокация С++, при которой просто вызоваются деструкторы в нужных местах (которые все равно будут вызываться при GC). Короче, деструкторы всегда в сумме займут одно и то же время, а вот оверхед есть только в GC.
Меньше фрагментация кучи, кстати.

Например, у нас есть три объекта в памяти, А, Б, В.
++++++АААА, ББ, ВВВВВВ+++++++ (+ — память занятая другими объектами)

Удаляем объект А:
++++++----, ББ, ВВВВВВ+++++++ Надо добавить освободившуюся память в список свободных блоков. +1 блок

Удаляем объект В:
++++++----, ББ,------+++++++ Надо добавить освободившуюся память в список свободных блоков. + 2 блока

Удаляем объект Б:
++++++----,--,------++++++++ 3 блока
++++++------------+++++++ или дефрагментация

GC же может пройтись по всем трем объектам, и потратить время только на добавление одного свободного блока, и итоговый оверхед будет меньше.
В режиме x86 оптимизатор полностью выкинул сортировку для std::array, поэтому получилось 0. В реальности работает чуть быстрее, чем C-style массив за счет отсутствия аллокаций.

asm volatile("");

А вообще следует закругляться со сравнением языков X vs Y на тривиальных задачах, особенно сравнивая C++ с Язык Y (всегда найдётся человек, который перепишет ваш код на SSE4.2+OMP, и сравнение завершится не в пользу последнего). Не верите — посмотрите на очень забавный сайт, где участники буквально соревнуются в искусном владении машинным кодом. Сейчас всех волнует не столько скорость, сколько потребление ресурсов и отзывчивость, если уж C++-разработчики добиваются весьма впечатлительных результатов, было бы любопытно посмотреть на языки с автоматическим управлением памятью в аналогичных условиях…
Мне неинтересно кто и как извращается. Я в свое время тоже извращался, упаковывая программы с окнами и IO в сотни байт на assembler, но вырос из этого возраста.

Еще раз повторю: мне интересно было сравнить быстродействие двух кусков кода, которые очень похожи на те, которые напишут 9 из 10 программистов.
UFO just landed and posted this here
Сделайте форк, добавьте тест в universal app и .NET Native.
Я тут по работе написал logging library на C++, со всевозможными блекджеками и шлюхами. По ходу дела обнаружил spdlog, и оптимизировал, пока не добился аналогичной производительности (около 3 миллионов форматированных сообщений в секунду). А потом сделал wrapper для C# (который делает только меньшую часть форматирования, и вызывает C++ код). Производительность C# меньше в 6 раз.
Это вы от Marshalling хотите быстродействия?
Если в C++ коде мне встречается настолько простой кусок кода, который при этом жрет приличное количество ресурсов, то я его в плюсах могу скомпилировать ICC или ручками вписать интринсики для SSE/AVX, благо что на плюсах это несложно. Обычно код удается подобным образом ускорить вдвое (но с большим разбросом, где-то и вчетверо, где-то на 20%). В шарпе подобное, насколько я понимаю, невозможно. На тривиальном коде до оптимизации, наверное шарп действительно благодаря JIT-у после «прогрева» будет медленнее «всего» на 20%, на оптимизированном вручную — сомневаюсь.

Но у меня в проектах подобные тривиальные куски кода где не требуется работа с памятью — редкость. Практически весь реальный код требует аллокации и освобождения памяти и там, сдается мне, шарпу резко станет хуже. Из интересного, к примеру, несколько дней возился с кодом который реализовывал многомерную аппроксимацию некоторой функции разложением в ряд Тейлора второй степени. Представьте себе квадратичный многочлен от N переменных, для которого сложение определено тривиальным образом, а умножение отбрасывает степени полинома выше второй. Математика там была тривиальной, а вот работа с памятью требовала эффективно аллоцировать и деаллоцировать кучу мелких объектов и объединять их затем в объекты покрупнее. Ну и взять N=600, несколько десятков тысяч операций с полиномами, и все это должно работать в рантайме, ибо является частью 3D-сканера который на лету должен обработать входящий поток данных. Ухайдокал рабочую неделю, но ускорил код вчетверо — не прибегая, заметьте, ни к какому «C-style» программированию с голыми указателями. С трудом представляю как на этой же задаче работал бы шарп.

И, все же в исходной задаче вызывает определенные сомнения методика работы с памятью. Я не спец по шарпу, поэтому мне сложно судить насколько адекватен вызов GC.collect в конце программы. Но на первый взгляд для сравнения это совершенно адекватный ход, поскольку финальное состояние программы в противном случае будет разным, ибо C++ код в конце выполнения никому ничего не должен, а шарповый имеет кучу несобранного мусора, на освобождение которого потом — уже вне измеряемого цикла — будет потрачено сколько-то времени. Не получается ли так, что Вы банально вынесли работу с GC за пределы измерения и, условно говоря, если Ваш цикл прокрутить не 100 раз, а 100.000 раз, то поначалу все будет хорошо, а на какой-нибудь 5.643-й итерации отжираемая небольшими кусочками память таки закончится и шарпу резко и внезапно поплохеет? В силу плохого понимания того почему GC.collect вдруг «портит оптимизацию» я допускаю что ошибаюсь и Ваш подход верен, но было бы как бы неплохо Ваш подход как-то обосновать.
Практически весь реальный код требует аллокации и освобождения памяти и там, сдается мне, шарпу резко станет хуже.


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

Математика там была тривиальной, а вот работа с памятью требовала эффективно аллоцировать и деаллоцировать кучу мелких объектов и объединять их затем в объекты покрупнее.
Если объекты короткоживущие, то C# сильно быстрее C++ будет. У C++ встроенный аллокатор медленный, в каждой второй advanced c++ книге выдумывают свой аллокатор по этому поводу.
Если мелкие объекты должгоживущие, то нужно в C# извращаться, создавая свои пулы из массивов структур.
Я не вижу проблем заменить аллокаторы, это несложно и в наших проектах там где это актуально используется.
Но здесь размер объекта не фиксирован и может сильно варьироваться, поэтому простой подход не прокатывает
И не надо катить бочку на плюсовый аллокатор. Штатный аллокатор (а точнее malloc) — это маленький шедевр программирования и он _очень_ эффективен для своей универсальности. Понимаете, проблемы заменить аллокатор, как таковой, в плюсах нет и если бы кто-то умел решать ту же задачу намного быстрее — все бы давно этим альтернативным аллокатором пользовались. Но на практике этого нет. Кастомные аллокаторы работают быстрее не потому что штатный медленный, а потому что они решают более простую задачу и благодаря учету ее специфики могут работать быстрее. Из более-менее универсальных аллокаторов которые при этом еще и быстрые мне вспоминается только интеловский аллокатор — он быстрее для многопоточных приложений, но расходует больше памяти.
Штатный аллокатор — страшный тормоз. Именно поэтому его заменяют
Если бы это было не так, то никто бы не занимался подменой аллокаторов.
Повторяю для тех кто не в состоянии прочитать комментарий еще раз: специализированные версии аллокаторов за счет использования специфики задачи или каких-то дополнительных компромиссов (например менее эффективного заполнения памяти) можно сделать быстрее. В основном игра стоит свеч только для тривиального случая «много одинаковых объектов». Но даже там какого-то невероятного прироста скорости нет.
Для тех кто не понял исходной проблемы — если бы аллокатор был достаточно быстрым, то не было бы нужны его переписывать.
А если бы в С++ была функция сделай_мне_хорошо() то на другие языки программирования никто бы и не смотрел. Ужасен язык где этой функции нет!

Мне как-то сложно вести беседу с человеком который не видит разницы между тезисами «штатный аллокатор — страшный тормоз» и «использование специфики задачи позволяет в некоторых ситуациях выжать дополнительные 20-30% производительности за счет использования специализированного аллокатора».
Тут вы чуточку не правы. malloc/new требуют перехода из user-mode в kernel-mode и из-за этого производительность страдает. Насколько страдает зависит от количества миллионов аллокаций (в секунду). Для new специфические аллокаторы и память могут гораздо эффективнее использовать. Но против malloc не приёма, если нет другого malloc.)
UFO just landed and posted this here
Чуточку же.)
Я вообще только про Windows выше написал, так как не знаю тонкостей работы менеджера памяти linux…

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

Отсюда возвращаемся к лейтмотиву всей трилогии статей и всех комментариев к ним: не посмотрев в профайлер вообще говорить не о чем.
UFO just landed and posted this here
Практически все менеджеры памяти работают в user-space.
Применительно к винде malloc работает на основе HeapAlloc, а последний выделяет под кучу память большим куском через VirtualAlloc (который правит page table и потому требует kernel space) и работает дальше в user-space, обращаясь к VirtualAlloc только для выделения больших блоков памяти.
Так что в винде malloc/new для блоков небольшого и среднего размера (<1 Mb примерно) как правило не требует перехода в kernel mode.
Не получается ли так, что Вы банально вынесли работу с GC за пределы измерения

Вообще-то не вынес. За время каждого теста в C# происходит как минимум одна сборка мусора и она учитывается в общем времени забега.
Ну она же очевидно не _весь_ мусор убирает (плюсы — весь)? Почему добавление GC.collect резко делает ситуацию намного хуже? Вы бы хотя бы график «время в зависимости от числа итераций» построили чтобы было видно когда происходит GC и сколько он занимает. И запустили бы тест, для объективности, на одноядерной машине, потому как «вычисления в одном потоке, GC во втором» — это шулерство, реальный вычислительно нагруженный код займет все ядра.

Я бы предложил все же вписать GC.collect в конец теста, чтобы он вызывался _один_ раз а не сто, но это время было все-таки учтено.
Представьте себе квадратичный многочлен от N переменных, для которого сложение определено тривиальным образом, а умножение отбрасывает степени полинома выше второй… Ну и взять N=600

А в какой задаче такое встречается? Может быть, и мне надо?

Казалось бы… многочлен — массив длиной (N+1)*(N+2)/2, индекс монома определяется по паре индексов переменных. Перемножение — все коэффициенты каждого на свободный член другого плюс двойной цикл по линейным коэффициентам. Если много многочленов от небольшого числа переменных, то придётся добавить пару таблиц мэппинга переменных. Где тут мелкие объекты?
Запись в виде плотной матрицы очень неэффективна, работа с несколькими матрицами 600x600, прямо скажем, не блистает быстродействием, а подавляющее большинство коэффициентов в этой матрице — нули. Эффективный код требует использовать одно из представлений разреженной матрицы и желательно — учитывать ее симметричность. Тут и возникают мелкие объекты переменной длины зависящей от степени заполнения матрицы.

Возникает эта конструкция в оптимизационной задаче на поиск оптимального расположения N поверхностей друг относительно друга. Параметризуем расположение поверхностей 6(N-1) переменными, записываем функцию ошибки для заданного расположения, строим для этой функции разложение Тэйлора 2-го порядка — получается квадратичная функция аппроксимирующая функцию ошибки, у которой минимум ищется решением линейной системы уравнений. Минимизируем квадратичное приближение — это не дает точного ответа, но дает приближение к нему, после чего повторяем тот же процесс разложения в ряд Тейлора уже в новой точке
Ясно. Я поступаю так: завожу матрицу 6N*(6N+1) (одну), потом для каждой пары поверхностей (у меня это облака) строю форму ошибки для их расположения (это плотная матрица 12*13), потом прибавляю её элементы к нужным элементам большой матрицы. Ну и потом — метод Гаусса. Использовать разреженность большой матрицы пока не пытался, у меня N не очень большие (максимум, 20-30).
CSR прекрасно попадает под определение мелкого массива переменной длины (один массив на матрицу)
Но здесь задача чуть проще, нет необходимости адресации произвольной строки, т.к. нет перемножения матриц (произведение любых двух квадратичных форм дает в выбранных ограничениях ноль). Зато и массивов два (линейная и квадратичная части)
И в терминах «ряда Тейлора» я над этой задачей не думал. Поступаю просто — записываю линейную часть сдвига точки в одном облаке, сдвига точки в другом, вычитаю одно из другого, прибавляю величину ошибки. Полученный линейный многочлен возвожу в квадрат, и все их складываю. Это для алгоритма «iterative closest point». Если бы подтягивал к касательной плоскости, поступал бы аналогично. То, что у сдвига сразу есть компоненты второго порядка, в голову как-то не приходило. Они действительно помогают?
Насчет помогают ли — вопрос спорный, т.к. сразу сделали с компонентами второго порядка.
Относительно старого подхода где поверхности позиционировались итеративно путем постепенного добавления +1 поверхности к уже поставленным N поверхностям он работает лучше :). А вот дают ли что-то компоненты второго порядка — не очень ясно. Теоретически могут, на практике толком не проверяли
А если сравнивать с подтягиванием всех поверхностей к текущему усреднённому положению? Понятно, что итераций будет больше, зато матрицы гораздо меньше.
Возможных вариантов много, мы не все пробовали, а текущий выглядит разумно эффективным :)
И просто из любопытства — каждая из поверхностей снимается неподвижным сканером, или сканер во время сканирования куда-то едет?
Сканер во время сканирования едет непредсказуемым образом (его держит в руках пользователь), мы это детектируем и компенсируем :)
Понятно. Он триангуляционный?
Нет, там достаточно малоизвестная технология, работает по принципу контрастного автофокуса. Я напишу потом статью о нем, интересная штука
Интересно. Нашёл парочку патентов, они используют специальные смещённые диафрагмы. Про вытаскивание глубины непосредственно из расфокусировки слышал лет 15 назад, но, по-моему, ничего из неё так и не сделали. Будет интересно почитать.
Сколько времени занимает реконструкция одного положения (без привязки)? И на каком процессоре?
Напрямую из расфокусировки тяжело что-то вытащить, но если добавить синхронизированную подсветку в плоскость фокусировки (по принципу конфокального микроскопа) и объектив с большой NA — то вполне реально. Дает очень высокую точность (20 микрон) и работает с полупрозрачными и бликующими объектами (мы сканируем зубы, так что для нас это важно, т.к. позволяет не покрывать зубы специальным порошком для сканирования).

Работает в реалтайме на не-топовом i7, латэнси первоначального (вполне приемлемого для визуализации) приближения <200 мс, а затем уже в менее жестких рамках нескольких секунд это приближении становится все точнее и лучше. Просто ведешь сканером и «открываешь» на экране поверхность.
А что мешает вам такую стать. написать?
Все эти «сравнения C++ и C#» заканчиваются в одном и том же месте: пойдите и предложите разработчикам драйверов, или ядер ОС, или движков баз данных, или браузеров, или ААА-игр, или протоколов, или видеокодеков использовать C#, ну потому что «почти так же по скорости, а писать удобнее». Дальше долго выслушивайте насмешки.
пойдите и предложите
ну потому что «почти так же по скорости, а писать удобнее».
А где об этом почитать?

Я лично вижу уже второй пост, который меряет время двух каких-то непонятных числодробилок, которые фактически вырождаются в замер скорости аллокации/сбора мусора, скорости работы памяти и работы оптимизирующих компиляторов. (И это помимо каких-то странных ограничений: «код на обоих языках максимально похожий» или «так пишут 9 из 10 программистов» (у автора явно накопилась большая статистика). На просьбы улучшить хотя бы то, что имеется — «ну форкай и напиши».)

А где кто-то пытался с шарпом залезть в ядро и драйверы — не вижу.
1, 2, 3 (таки 9 из 10 программистов не знают про std::swap?), 4.
Специально для вас сделал.
.NET Native работает примерно с той же скоростью, что и C++.
На одного программиста баз данных и драйверов приходится от 100 до 1000 (навскидку) программистов, которые пишут прикладные программы.

Если вы пишите драйверы, то у вас и вариантов мало, кроме C.
Смотря на статистику распространения C# и С++ по всяким разным рейтингам мы увидим одни и те же числа, ну, плюс/минус 30%, но уж никак не 1000х.
Ух, прям мейнстрим!
Мейнстрим — понятие относительное, сегодня там одно, а завтра — совсем другое.

А если серьезно, то все понимают, что есть области, где недостаточно «почти так же по скорости», вне зависимости от удобства написания. Но с уменьшением «почти» этих областей становится меньше, и то, что раньше на «удобных» языках писать было совершенно непредставимо, сейчас пишется все чаще и чаще.
Мест, где небольшой вроде бы прирост производительности может существенно сэкономить байты\секунды\доллары тоже становится больше и кое-что наоборот с «почти такого же по скорости» переписывается на чём-то уровнем пониже, пример — habrahabr.ru/post/261205
Мест, где небольшой вроде бы прирост производительности может существенно сэкономить байты\секунды\доллары тоже становится больше

Это, на самом деле, очень интересный вопрос — становится ли таких мест больше в процентном отношении, или же нет.
В некоторых случаях в такие проекты не только шарперов на пушечный выстрел не подпускают, но и плюсовиков.
UFO just landed and posted this here
Unity видели? На нем довольно солидные игрушки делают.
Выше уже приводили и пример и банальное контрзамечание что сам Unity на C++ написан
Да неплохой двиг, а есть пример неплохого движка не на С++?
Когда-то я писал медиасервер и в тестах надо было вытянуть + одно full HD качество
Оставим за скобками вопрос можно ли подобные вещи писать на C# (что бы при этом на 3-х ОС минимум работало)
Но конкретно в этом проекте функции копирования памяти при преобразовании цветовых пространств удалось ускорить в разы
Я развернул циклы, сделал так что бы эффективное использовался кэш
А мой коллега добавил AVX инструкции там где это было необходимо
Результат — мы это сделали
Это банальный пример, но от этого он не становится менее «реальным» и «статистически» пригодным для Ваших рассужденй
В целом — не вижу никакой пользы от этих двух статей. Нет универсального языка, который бы покрывал любой вектор целевых задач с любым множеством критериев оптимальности. Поэтому вравнивать несколько языков в виде статьи бесмыссленно — много критериев и нюансов. А говорить что один принципиально лучше другого — вообще абсурд. Адекватный специалист понимает, что язык — это инструмент.
В частности — оценивание языка критерием скорости работы априори субъективно — невозможно покрыть все возможные задачи и сравнить результаты, так как: критерии оценки разных потребителей сильно разнятся, некоторые задачи невозможно или нецелеобразно реализовать на одном из двух сравниваемых языков, да реализовать можно по-разному. В итоге выхлоп статьи нулевой и ее единственный вывод — что так делать не нужно.
Любопытно было бы заменить в этой задаче массив интов на массив структур и сортировать по одному из полей. В C++ влияние вполне предсказуемое, а вот не будет ли это катастрофой в C#? (просто предположение — я в C# вообще никак)
При правильной реализации — нет, не будет.
Хотелось бы поблагодарить автора за статью и особенно пример на .NET Native, а также задать несколько вопросов:

1. Удалось ли понять за счет чего .NET Native несколько медленнее С++, не получалось ли сравнить disassembly?
2. Есть ли возможность использовать .NET Native с .Net Framework 4.0 (чтобы «разогнать» энтерпрайс, которому необходима поддержка XP:( )
3. Какие видятся причины для того чтобы не переходить на .NET Native с обычного managed С#?

В качестве ответа на 2 и 3 самому себе:
Похоже обычные десктопные приложения нельзя построить с .NET Native, а построить можно только приложения для Windows Store. Так ли это?
Не знаток в такого рода деталях, но вроде даже в блоге Microsoft упоминалось, что данный момент так. Однако, вроде бы можно вручную с помощью какого-то инструмента скомпилиравать в Native (что не тоже самое, как минимум технология другая). Обычно это происходит автоматически для критических участков кода — система сама распознает. Но есть программы, вов ремя установки которых, установщик вызывает этот инструмент чтобы сразу все свои библиотеки скомпилировать под платформу.

Articles

Change theme settings