Специализни шаблонца! (udpn) wrote,
Специализни шаблонца!
udpn

10+ причин почему не стоит цитировать глупости love5an.

В ответ на.

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

Дискуссии длились несколько лет, и у меня никак не найдётся возможности полностью передать всю их глубину и содержательность. Откомментировал только то, что смог разобрать. Если остальное мне кто-нибудь объяснит и конкретизирует, буду рад обсудить. Также слегка откомментировать взялся мой коллега shuffle_c.
>> медленная компиляция
Медленная компиляция была, в основном, когда я работал с Boost. Причины для этого другие, а именно неоднократный препроцессинг одних и тех же файлов, а также устаревшие метавычисления на шаблонах. Впрочем, эти проблемы решаются свежими расширениями языка. Функции времени компиляции, объявленные с ключевым словом сonstexpr, отрабатывают существенно быстрее. С появлением вариадических шаблонов огромное количество определений шаблонов с разной арностью также потеряло смысл. Правда, boost ещё не переписали, но это, как я понимаю, вопрос поддержки свежих фич компиляторами. В любом случае, жаловаться на медленную компиляцию в языке, где вычисления времени компиляции тьюринг-полны, и используются для чего-нибудь вроде генерации парсеров (boost::spirit) довольно абсурдно.
sh: Precompiled headers очень существенно увеличивают компиляцию, почти как в C# получается. у нас в проекте они не используются, но и то я не сказать, что жалуюсь на скорость.
>> частые «internal error» в компиляторах
Даже несмотря на то, что я, в своё время, эти самые С1001 в студии выискивал и докладывал в ЖЖ и в багтрекер, я бы не сказал, что их так уж много. Если искать их намеренно, скажем, в Glasgow Haskell Compiler, то уже довольно простой пример из TaPL с экспоненциально растущими типами во вложенных let переполняет память и подвешивает компилятор.
>> код плохо читается и его сложно поддерживать
А уж код на ранее упомянутом Haskell и подавно. Почему-то никто не вменяет это плохому дизайну языка. Или я просто не слышал? Если серьёзно, то учите С++. Прочтите стандарт хотя бы.
>> разбор кода различными инструментами, вроде IDE, и его генерация - сильно затруднены
В общем-то, проблемы авторов IDE. AFAIK, VS2013 весьма неплохо с этим справляется. Хотите подсвечивать синтаксис? Есть Winnie Colorizer. Необходимые знания для написания своего аналога подтягиваются из задания PA1 курса CPPGM. Проблема, скорее, в компетентности программистов. Генерация кода на С++ не нужна, поскольку там есть средства метапрограммирования из коробки. Впрочем, у меня с генерацией тоже проблем не было. Писал транслятор из лиспа в шаблоны.
sh: Даже VS 2012 с этим хорошо справляется, Visual Assist тоже очень хорошо начал. А скоро ожидается тулза от jetbrains, так что этот вопрос почти закрыт.
>> ручное управление памятью
Основная причина для его введения -- правило zero overhead. В языках со сборкой мусора обычно тяжело избавиться от нежелательного поведения сборщика. Обычно мы имеем overhead по производительности и прочие опасные эффекты, что для системного программирования попросту недопустимо.
sh: GC, по факту, возможна, благодаря поддержке со стороны языка в С++11. но, по факту, она никому все равно не нужна. Ручное управление это хорошо, потому что приемы управления используются не только для памяти, а для любых ресурсов
>> утечки памяти
Наверное, отстал от технологий, но неужели автоматическая сборка циклического мусора перестала быть проблемой? То есть, конечно, она описана ещё в драгонбуке, но методы-то не эффективные, или порождают слабые ссылки, или не параллелятся, или ещё что-нибудь такое. Может быть, я открою кому-нибудь глаза, но задача своевременной сборки мусора вообще алгоритмически неразрешима, и люди пользуются субоптимальными решениями. Разве искать причину утечек легче во внутренностях рантайма, чем в своём коде?
>> висячие ссылки
NullPointerException?
sh: weak_ptr
>> сегфолты
Продолжить предложение: “Разница между ошибками, генерируемыми ОС и рантаймом, заключается в том, что…”
Впрочем, у меня такого почти не бывает. Наверное потому, что я использую STL, а не CRT.
>> стандартные средства, как то malloc/new, работают медленно
Потому что используют вызовы ОС. Нужна скорость -- используйте placement new. Кроме того, в С++ никто 1) не использует malloc; 2) не запрещает перегрузить new на более эффективный.
sh: Медленно -- не аргумент. в других языках, что ли, быстрее?
>> Никакого ABI
Использование С++ на многих платформах подразумевает, что наличие, к примеру, строго заданного порядка следования аргументов на стеке или endianness приведёт к тому, что использовать язык на разных платформах будет нельзя. Для этого там есть соответствующие прагмы, __declspec, naked функции и прочая. Не понимаю, как можно 1) говорить, что у языка нет ABI, учитывая, что ABI задаётся платформой; 2) говорить это про крайне кроссплатформенный С++. Под ABI подразумевалось что-то другое?
>> Нестандартизированный и непредсказумый name mangling
>> Дублирование функционала Си
Обратная совместимость. Дублирования нет, поскольку использование функционала Си в С++ is highly discouraged. С тем же успехом можно говорить, что есть дублирование функционала ассемблера, поскольку в большинстве реализаций есть возможность делать ассемблерные вставки.
>> запутывает новичков
Новичков запутывают плохие книги и плохие преподаватели. Любому новичку, использующему гугл на уровне падована, сразу удаётся найти что-нибудь вроде вот этого списка (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list), где использовать const char *, scanf и printf никто не посоветует.
>> препроцессор - шаблоны
Вы всё ещё вспоминаете ту одну первобытную реализацию С++, где шаблоны инстанцировались посредством текстовой подстановки фактических аргументов в их тело?
>> указатели - ссылки
Ссылки это синтаксический сахар для некоторых применений указателей. Арифметика указателей нужна для написания эффективного кода, и назвать эти два средства языка дублирующими друг друга нельзя.
sh: r-value ссылки при этом имеют совершенно иную семантику.
>> структуры - классы
Они не дублируют друг друга. Структуры и классы различаются спецификатором доступа по умолчанию.
>> stdio - iostream
сstdio предоставляет нетипизированные средства для ввода-вывода и в С++ не используется.
>> Отсутствует даже такой функционал, как вменяемая работа со строками и многомерные массивы
Для строк есть string. Для всего остального есть boost, являющийся полигоном для расширений стандартной библиотеки языка. Многомерные массивы там есть. Из boost в STL этот функционал не перенесли, поскольку научились не делать поспешных решений, и предпочитают сначала подумать над вводимыми в язык возможностями. На все возможности времени комитета стандартизации не хватает.
sh: чем vector<vector… не многомерный массив?
(Полагаю, дело в затратах на хранение дополнительных размерностей для jagged массивов, если автор задумывался о zero overhead, в чём я сомневаюсь.)
>> Юникод
wstring, codecvt?
>> Слабая типизация
“Слабая” это прилагательное, а не термин. Действительно сильная типизация есть только в небольшом наборе языков вроде Coq, где можно получить гарантии об отсутствии практически любого вида нежелательного поведения в программе на уровне системы типов, т.е. во время компиляции. Если вы про то, что указатель можно разыменовать, так, извините, и в сильно типизированном Haskell я могу использовать unsafe-функции или определять функции с неполным pattern’ом со схожими эффектами.
>> const не дает абсолютно никаких гарантий
Адекватные люди не используют const_cast просто так.
>> практически никакой интроспекции
Zero overhead.
>> передача объектов по значению
Кто хочет передавать по значению, пусть передаёт. Обычно передают как const &. Конструкторы копирования предоставляют все возможности для управления владением ресурсами. Есть RAII. О чём речь?
>> проблема ромба по дефолту не разрешается никак
Виртуальное наследование. По дефолту -- пути наследования. Почему не виртуальное наследование по дефолту? Zero overhead.
sh: по дефолту, если это и проблема - она тут же вылезет, а как исправить, нужно уже знать - не просто же так ромб делается
>> исключения в конструкторах гарантированно влекут утечку памяти
Вообще-то исключения в конструкторах это вполне обычное дело. Как влекут?
>> деструктор можно вызывать до выхода из блока кода, или до delete
В общем-то, проблемы человека, который делает это, не зная, зачем это нужно (а нужно это как раз для использования всяких placement new, где компилятор не способен вызвать вовремя деструктор автоматически, поскольку не отслеживает местонахождение объекта).
>> pure virtual function call
Проблемы кривизны рук.
>> деструкторы обязаны быть виртуальными
>> по дефолту - не виртуальные
Zero overhead.
>> никаких интерфейсов, только классы
>> порядок инициализации статических членов классов не определен
При наличии в конструкторах сайд-эффектов, зависимых друг от друга, объект-обладатель темпорально первого эффекта должен управлять обладателями последующих. Обычно делается через наследование. Порядок инициализации не нужен.
>> private, public и protected не дают никаких гарантий сокрытия данных
Нужно абсолютное сокрытие данных? Криптографически аппаратно разделённые области памяти и криптографически стойкий интерфейс до монитора?
>> отсутствие «свойств»
Свойства, мутаторы и прочее дерьмо из джавки в С++ переносят джависты. В самом языке для этого есть классы, конструкторы приведения типов, перегрузка операторов приведения типов. Создаётся один раз тип наподобие “число не более 5”, создаются поля этого типа. При присваивании полю значения 6 отрабатывает проверка в конструкторе, выбрасывается исключение. Code reuse существенно возрастает. Я об этом, кстати, уже писал. http://udpn.livejournal.com/59975.html
>> «friend» нарушают инкапсуляцию
Ключевое слово friend нужно для реализации вещей вроде множественной диспетчеризации, для трюка Бартона-Накмана и прочих полезностей.
sh: «public» нарушают инкапсуляцию, что же делать?
>> [шаблоны] километровые и плохо читаемые сообщения об ошибках при компиляции
static_assert добавлен в язык. Разработчики библиотек, связанных с метапрограммированием, увы, должны с такими сообщениями мириться, пока не создана IDE, позволяющая отлаживать compile-time.
sh: Я не знаю, можно ли аппелировать к опыту, но как правило от этих сообщений нужно только место, где оно произошло.
>> [шаблоны] обязаны содержать реализацию в заголовочных файлах
Использовать заголовочные файлы в С++ это моветон. В С++ используются файлы .hpp, которые представляют собой попросту вынесенные блоки кода. Впрочем, всё равно ведь вы неправду написали, там есть extern template.
>> [шаблоны] позволяют генерировать некорректный код
Т.е. нужно убедиться в том, что тьюринг-полная система сгенерирует правильный код? Не кажется, что задача алгоритмически неразрешима?
>> отсутствие finally/unwind-protect
Или вкратце: в С++ для этого есть RAII.
>> заставляет городить классы ради одних деструкторов
Вопрос структурного программирования против объектно-ориентированного, в общем-то. Если лень заводить классы, используйте функции.

Резюме: лучшая стратегия на авторском уровне познания языка формулируется как "заткнись и пиши".
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 37 comments