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



Мы поможем в написании ваших работ!


Мы поможем в написании ваших работ!



Мы поможем в написании ваших работ!


ЗНАЕТЕ ЛИ ВЫ?

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



Результирующий объём исполнимого кода

Использование шаблонов C++ представляет собой параметрический полиморфизм на уровне исходного кода, но при трансляции он превращается в ситуативный (ad hoc) полиморфизм (то есть перегрузку функций), что приводит к существенному увеличению объёма машинного кода в сравнении с языками, имеющими истинно полиморфную систему типов (потомками ML). Для снижения размера машинного кода пытаются автоматически обрабатывать исходный код до этапа раскрутки шаблонов[23][24]. Другим решением могла бы быть стандартизованная ещё в 1998 году возможность экспорта шаблонов, но она доступна далеко не во всех компиляторах, так как её трудно реализовать[25][26][мнения 4] и для импорта библиотек шаблонов С++ в языки с существенно отличной от С++ семантикой она всё равно была бы бесполезна. Сторонники С++ оспаривают масштабы раздувания кода как преувеличенные[27], игнорируя даже тот факт, что в Си параметрический полиморфизм транслируется непосредственно, то есть без дублирования тел функций вообще. При этом сторонники С++ считают, что параметрический полиморфизм в Си опасен — то есть более опасен, чем переход от Си к С++ (противники С++ утверждают обратное — см. выше).

Потенциал к оптимизации

Из-за слабой системы типов и изобилия побочных эффектов становится крайне затруднительным эквивалентное преобразование программ, а значит и встраивание в компилятор многих важных оптимизирующих алгоритмов — автоматического распараллеливания, устранения ненужных промежуточных представлений данных и вычислений, лямбда-лифтинга, вызовов процедур с передачей продолжений, суперкомпиляции и др. В результате реальная эффективность программ на С++ ограничивается имеющейся квалификацией программистов и вложенными в конкретный проект усилиями, и «небрежная» реализация может существенно уступать по эффективности «небрежным» реализациям на языках более высокого уровня, что подтверждается сравнительными испытаниями языков[28]. Это является существенным препятствием против применения С++ в индустрии data mining.

Эффективное управление памятью

Потенциал к повышению эффективности управления памятью весьма ограничен. Хотя существуют многочисленные реализации автоматической сборки мусора, использование более эффективных способов управления памятью (таких как статический вывод регионов) для конкретной библиотеки невозможно (точнее, это привело бы к реализации поверх языка С++ интерпретатора нового языка, сильно отличающегося от С++ как большинством объективных свойств, так и общей идеологией) по причине необходимости прямого доступа к AST. Для автоматического управления памятью в С++ традиционно используются т. н. «умные указатели», которые в определенных условиях могут иметь худшую временную сложность, чем сборка мусора[пояснения 6]. Ручное же управление памятью значительно снижает эффективность самих программистов (см. раздел Результативность).

Замедление Си

В условиях узко ограниченных вычислительных ресурсов (например, при программировании многих встраиваемых систем) неприемлемыми могут оказаться самые разные аспекты С++, отличающие его от Си. Механизм виртуальных функций реализуется посредством позднего связывания, то есть требует динамического вычисления реального адреса функции (RVA). Ещё более существенные накладные расходы возникают в связи с созданием временных объектов при передаче параметров в функции и возврате (использование конструктора копирования). То есть простая адаптация программы на Си под идеологию С++ уже вызывает замедление, которое в определённых условиях может оказаться недопустимым. Наконец, встраиваемая система может просто не располагать тем объёмом памяти, который необходим для библиотеки времени исполнения (RTL), сопровождающей любую программу на С++. Хотя формально стандарт не накладывает ограничения на состав этой библиотеки для конкретной программы на С++, при полном её удалении уже нельзя говорить об использовании языка С++ в качестве инструмента, так как конструкции языка, связанные с RTL, окажутся утраченными (даже операции new/delete и new[]/delete[]) — соответственно будет отличаться и идеология программирования (несвязанные с RTL возможности - шаблоны, более строгая типизация и т.п. - останутся).

Результативность

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

Ручное управление памятью

Как отмечается в исследованиях[29], программисты на Си тратят 30% — 40% общего времени разработки (не считая отладки) только на управление памятью. Если в низкоуровневых задачах (для которых разработан Си) это оправданно, то в прикладных задачах широкого спектра (на которые претендует С++) это не только является напрасным, но и чревато ошибками. Для С++ существуют библиотечные средства автоматического управления памятью, но они применяются далеко не всегда, кроме того, их эффективность ограничена (см. также разделы Отсутствие возможностей и Вычислительная производительность).

Менеджмент проектов

Перечисленные выше факторы делают сложность менеджмента проектов на С++ одной из самых высоких в индустрии разработки ПО.

Джеймс Коггинс, в течение четырех лет ведущий колонку в The C++ Report, дает такое объяснение:
— Проблема в том, что программисты, работающие в ООП, экспериментировали с кровосмесительными приложениями и были нацелены на низкий уровень абстракции. Например, они строили такие классы как «связанный список», вместо «интерфейс пользователя», или «луч радиации», или «модель из конечных элементов». К несчастью, строгая проверка типов, которая помогает программистам C++ избегать ошибок, одновременно затрудняет построение больших объектов из маленьких.

— Ф. Брукс, Мифический человеко-месяц

Идеология компонентности

Объектная модель С++, унаследованная от Симулы и дополненная двумя формами множественного наследования (простой и виртуальной), имеет не только объективные проблемы, но и опасную идеологию. По словам создателя Smalltalk Алана Кэя, объектная модель «Алгол с классами» обладает худшими характеристиками качества, чем модель «всё — объект»[14], и в этом смысле С++ уступает своему ближайшему конкуренту Objective-C: показатель повторного использования кода оказывается крайне низким (см. раздел Полиморфизм); рефлексивное метапрограммирование — невозможным; показатели понимаемости, модифицируемости и тестируемости — слабыми (см. раздел Отсутствие возможностей). Реализация указателей на методы классов не стандартизирована, и их размер в различных компиляторах варьируется от диапазоне 4 до 20 байт, что значительно снижает портируемость программ с их использованием[30]. Принятая в сообществе С++ характерная методология декомпозиции задач приводит к проектным решениям, не доказуемым математически и неадкватным предметной области, и потому угрожающим неоправданными затратами и скрытыми ошибками. Традиционно в математике (и, соответственно, в более строгих языках программирования) понятие «класс» отождествляется с понятием «множества» (или реже «категории»). Понятие «наследования классов» в информатике традиционно означает создание «подклассов», то есть «подмножеств» или «подтипов» (по Карри, тип определяется как множество значений). В С++ эта традиция не соблюдается (в соответствии с принципом «Дать программисту свободу выбора, даже если это даст ему возможность выбирать неправильно» — см. раздел Философия C++[пояснения 7]), и наследование зачастую используется вместо вложения — то есть определение нового типа на основании более простых взаимно-ортогональных типов осуществляется посредством создания не совершенно нового типа, инкапсулирующего эти типы (и ортогонального им), а «их общего подтипа» (несмотря на то, что ортогональность означает отсутствие точек соприкосновения). Например, в [31] приводится учебно-рекомендательный пример реализации типа (класса) «список» как подтипа (подкласса) от «одного элемента этого самого списка», и базовый класс (надкласс) «элемент несуществующего списка», хотя и позиционируется как абстрактный скалярный тип (контейнер для некоего единственного значения), тем не менее содержит операции, присущие агрегатным типам и внешним интерфейсам (функции доступа к другим элементам несуществующего списка, внешним по отношению к текущему объекту), однако не может расцениваться как агрегатный тип и не предназначен для самостоятельного использования. Такое отношение типов является абсурдом с т.з. математики и, как следствие, невоспроизводимо на более строгих языках. Идеология некоторых библиотек также прямо опирается на возможность приведения типов вверх и вниз по иерархии классов (операции static_cast и dynamic_cast), подтверждая, что типобезопасность не входит в традиции языка. При множественном наследовании картина может быть ещё хуже. Ошибочность проектных решений, принятых в соответствии с этой идеологией, может обнаруживаться на поздних этапах разработки и из-за высокой вязкости требовать повторной разработки значительных частей проекта. Ярким примером является описанный в[15] случай:

Пример подобной проблемы описан в [C.Potts, "Software-Engineering Research Revisited, " IEEE Software (Sept., 1993)] и [M.Lubers, C.Potts & C.Richter, "Developing Initial OOA Models, " Proc. Intl. Conf. Software Eng., Los Alamitos, Calif. (1992)]. Для исследования применимости объектно-ориентированной декомпозиции к системам разного рода были проанализированы три случая. Один из них был реальным проектом разработки системы наведения ракеты Томагавк. Разработчики сочли, что все ракеты можно разделить на подклассы в соответствии с видом боеголовки и навигационными характеристиками. Также их можно разделить на тактические и учебные. Эти две таксономии были практически ортогональны, и было принято решение использовать множественное наследование для применения этих категорий к конкретным видам ракет. Однако, на более поздней стадии разработки было обнаружено, что ортогональность нарушена: хотя некоторые виды учебных ракет могут нести боеголовки, ядерные ракеты не могут. Продолжение принятого подхода к построению архитектуры привело бы к неэлегантным и искусственным моделям, скрывающим под массой деталей исключительные ситуации, которые легко упустить.

Оригинальный текст (англ.)

An example of this problem is described in [C.Potts, “Software-Engineering Research Revisited,” IEEE Software (Sept., 1993)] and [M.Lubers, C.Potts & C.Richter, “Developing Initial OOA Models,” Proc. Intl. Conf. Software Eng., Los Alamitos, Calif. (1992)]. Three case studies were designed to evaluate how suitable different flavours of object-oriented analysis were for different types of system. One of the case studies was a real project to develop the engagement system for the Tomahawk missile. The developers found that they could divide missiles into subclasses according to their warhead and navigational properties. They could also be categorised according to whether they were tactical or exercise missiles. These two taxonomies were almost entirely orthogonal, and this suggested that they use multiple inheritance to make use of both categorisations. However, later on in the development it was found that the orthogonality broke down: although some types of exercise missiles can carry warheads, nuclear missiles cannot. Continuing with the original top-level design would have produced inelegant and artificial models, with the exceptional case buried in a mass of details and easy to miss.

— Mаrtin Ward в [15]

Качество и культура программирования

В ответ на объективную критику, сторонники C++ утверждают, что ничто не вынуждает программиста на C++ использовать «плохие» языковые средства, если он умеет использовать имеющиеся в языке и предназначенные для этой же цели «хорошие», и что программист на C++ имеет возможность выбора в соответствии с личными предпочтениями и уровнем знаний,— тогда как другие языки обычно предлагают чётко очерченный баланс между порогом вхождения и результативностью программиста. Проблема заключается именно в условии понимания программистом целей, для которых были предусмотрены те или иные возможности. Лозунг С++ «не навязывать „хороший“ стиль программирования» имеет достоинством лишь снижение порога вхождения; с т.з. качества ПО он является недостатком (см. типобезопасность) — при высоких требованиях качества (не только в аспекте надёжности) предпочтительными являются языки с семантикой, сводящей к минимуму риск влияния человеческого фактора, то есть именно навязывающие «хороший» стиль программирования (Ada, SML, Haskell, BitC) — но такие языки имеют более высокий порог вхождения. Однако, при анализе свойств С++ как инструмента разработки, низкий порог вхождения и ожидание высокой результативности заявляются его сторонниками одновременно, без противопоставления — это один из аспектов, в котором С++ претендует на «универсальную применимость» (см. Философия C++). Но тогда, поскольку все элементы семантики C++, отсутствующие в Си, были заимствованы из других языков (зачастую чужеродных Алголу),— очевидно, что для адекватного и аккуратного применения взаимно противоречивых возможностей и избегания провоцируемых ими ошибок, программист на С++ должен изначально знать непосредственно эти языки и лежащую в их основе формальную базу. Этого, однако, не наблюдается: практика показывает, что преимущественно положительная оценка и предпочтение использования C++ характерны лишь для тех, кто не владеет ни одним языком, не являющимся потомком Алгола (не считая ограниченного набора узко специализированных языков, таких как SQL, HTML, Perl и др. — зачастую даже не полных по Тьюрингу); программисты же более высокого уровня обычно отзываются о C++ далеко не так оптимистично и стараются его избегать, если нет вынужденности поддерживать legacy code[мнения 5]. Обобщение этих мнений даёт основания полагать, что существует обратно-пропорциональная зависимость между умением программировать на С++ в «хорошем» стиле и желанием использовать С++ в качестве инструмента разработки — из которой следует, что защищающие С++ программисты, по всей видимости, заблуждаются в отношении того, что именно следует считать «хорошим» стилем программирования. В частности, Линус Торвальдс говорит, что использует субъективное мнение кандидатов о С++ в качестве критерия отсева (предпочитающие язык С++ языку Си отвергаются)[мнения 3]. Таким образом, контр-аргументация сторонников С++ в аспекте качества и культуры программирования оказывается не убедительна и не перекрывает объективную критику. При этом, сама по себе попытка перевести объективную критику в разряд субъективной в сочетании с позиционированием С++ как «универсально применимого» языка, очевидно, являет собой попытку существенно снизить порог вхождения для самой профессии программирования — заявить, что высококвалифицированным в принципе может считаться программист, использующий единственный язык общего назначения для всех задач.

Исправление исправного

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

Сложность ради самой сложности

Как уже отмечено в разделе Отсутствие возможностей, принцип С++ «не платишь за то, что не используешь» последовательно приводит к увеличению на порядки стоимости развития и поддержки продукта. Другими словами, пока программист на С++ «не платит за то, что он в С++ не использует», его работодатель переплачивает за использование языка С++ и программиста на нём. Это не является аргументом для сторонников С++ в пользу смены инструмента разработки — напротив, С++ определяется ими как «мощнейший» именно потому, что он изобилует опасными взаимно-противоречивыми возможностями, возлагая ответственность за доказательство их корректности на программиста. При кажущейся абсурдности такого определения, ему существует психологическое объяснение, данное Эриком Реймондом — это делает язык сам по себе почвой для личностного самоутверждения, облегчая возможность субъективно превращать процесс разработки из средства в самоцель:

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

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

— Эрик Реймонд в [32]

Саботаж

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

#define if(a) if(rand())

 

#define j i

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

Ненадёжность продукта

Неоправданное обилие побочных эффектов (даже в таких простых операциях как индексация массива), в сочетании с отсутствием контроля со стороны системы времени исполнения языка и слабой системой типов, делает программы на С++ традиционно нестабильными, что исключает применение C++ при высоких требованиях отказоустойчивости. Кроме того, это увеличивает длительность самого процесса разработки[28]. Общеизвестные сообщения об ошибках при фатальных крахах прикладных программ, такие как «Access violation», «Pure virtual function call» или «Программа выполнила недопустимую операцию и будет закрыта», присущи в наибольшей степени именно С++. (Контр-примеры: для потомков ML фатальный крах в принципе невозможен — программа может навечно уйти в расчёты или выдать сообщение об ошибке, но никогда не обрушится — кроме того, контроль типов заметно сокращает время разработки[28]; семантика Форта обеспечивает практически гарантированное выявление ошибок на этапе разработки; Eiffel, Smalltalk и Erlang предоставляют простые способы обработки любых возможных ошибок самой программой без обрушения.)

Влияние и альтернативы

Ввиду изобилия критики в адрес С++, неоднократно предпринимались попытки предложить альтернативы C++, как для прикладного, так и для низкоуровневого программирования (не заявляемые как «универсально применимые» языки).

Одной из первых альтернатив в прикладном программировании стал язык Java, разработанный Sun, который часто ошибочно считают прямым потомком C++. На деле в Java от С++ нет ничего, кроме синтаксиса — семантика Java унаследована от языка Модула-2, и основы семантики C++ (такие как система типов, основанная на адресной арифметике, ручное управление памятью, умышленный отказ от фундаментального принципа ООП «всё — объект», и др.) в Java не прослеживаются. Семантика отдельных операторов также отличается: например, безусловный переход в Java отсутствует, а ключевое слово goto использовано для финализации (разновидности условного перехода). Кроме того, элементы семантики Си, унаследованные из Lisp (такие как функции высших порядков, функции с неограниченным числом аргументов и тернарная условная операция), в Java отсутствуют. Нет в Java и макроопределений времени компиляции. Всё это заметно меняет идеологию программирования на языке (хотя и сохраняет её в рамках общей идеологии потомков Алгола). Для улучшения коньюнктуры создатели Java выбрали синтаксис C++ и поощрили их сравнение в печати. Учитывая всё это, а также генеалогию языков (Modula-2 является потомком Симулы, как и С++, но им не является Си), Java правильнее называть «троюродным племянником» С++, нежели «наследником». По тому же пути пошла компания Microsoft, предложив язык C#.

После того, как было получено общественное признание Java и C#, были произведены попытки совмещения безопасности и скорости разработки, характерных для Java и C#, с эффективностью C++ — так появился язык D и диалект Managed C++, не получившие широкого признания. Одновременно с развитием Алголовского направления, сторонники функционального программирования и рефлексивного метапрограммирования предприняли попытку совместить модель типизации Хиндли-Милнера и макро-подмножество Common Lisp с языком C#, создав язык Nemerle. Его также зачастую стали рассматривать как «конкурент C++», что способствовало росту популярности функционального программирования и рефлексивного метапрограммирования[33] и побудило Microsoft дополнить базовый комплект своей среды разботки для C++ и C# (Visual Studio) компилятором языка F# — диалекта ML, адаптированного для совместимости с C#. Резонно полагать, что те же цели преследовали разработчики языков Scala и JavaScript — гибридных функционально-объектно-ориентированных языков, также унаследовавших синтаксис С++, но ориентированных на совместимость с Java.

Старейшим конкурентом С++ в задачах низкого уровня является Objective-C, совмещающий Си с объектной моделью Smalltalk. Из-за их соперничества долгое время полагалось, что эффективность и низкоуровневые возможности Си могут использоваться в сложно структурированных высокоуровневых задачах только посредством облачения их в ту или иную объектную модель. Однако, накопленные за многие годы достижения в сфере ФП позволили предложить альтернативный путь развития языка Си — совмещение его не с объектно-ориентированным, а с аппликативным программированием, то есть улучшение абстракции, строгости и модульности низкоуровневых программ посредством обеспечения не инкапсуляции изменяемого состояния, а наоборот, предсказуемости поведения и ссылочной прозрачности. Примерами работ в этом русле служат языки BitC, Cyclone и Limbo. Хотя есть и успешные попытки применения ФП в задачах реального времени без интеграции со средствами Си[34][35], всё же на данный момент (2013 г.) в низкоуровневой разработке применение в той или иной мере средств Си имеет лучшее соотношение трудоёмкости с результативностью. Много усилий было приложено разработчиками Python и Lua для обеспечения использования этих языков программистами на С++, так что из всех языков, достаточно тесно связанных с ФП, именно они чаще всего отмечаются в совместном использовании с С++ в одном проекте. Наиболее значимыми точками соприкосновения С++ с ФП можно считать привязки разработанных на С++ библиотек wxWidgets и Qt с характерной для С++ идеологией к языкам Lisp, Haskell и Python (в большинстве случаев привязки к функциональным языкам делают для библиотек, написанных на Си или на других функциональных языках).

Прямой потомок С++ на данный момент лишь один — язык D.

Сравнение Java и С++

См. также: en:Comparison of Java and C++

Java и C++ часто сравниваются как языки, унаследовавшие синтаксис Си, несмотря на огромные различия на всех уровнях, от семантики до сферы применимости. Можно сказать, сравнение С++ с Java идёт вторым по частоте после сравнения С++ с Си.

Целевая ниша

Java позиционируется для весьма конкретного сектора промышленности: безопасный язык с низким порогом вхождения для разработки прикладных пользовательских приложений широкого рынка с высокими показателями портируемости[36] — и с этой задачей справляется. С++ претендует на «универсальную применимость» во всех задачах для всех категорий программистов, но не удовлетворяет в полной мере требованиям ни одной из заявленных сфер применимости (см. раздел Критика).

Исполнение программы

Java имеет формальную семантику, ориентированную на интерпретацию, но код Java компилируется в промежуточный код, который непосредственно перед запуском программы компилируется в машинный (иногда говорят об интерпретации байт-кода, но в данном случае это неверно — у современных наиболее распространённых сред исполнения Java оба этапа трансляции являются полностадийными, не ограничиваясь работой в рамках AST, с соответствующим сужением возможностей). C++ имеет естественную семантику, ориентированную на компиляцию, так что уже на аппаратной Java-машине был бы крайне неэффективен и ограничен по возможностям. Одно это определяет разницу в сферах применения языков: Java нецелесообразно использовать в низкоуровневом программировании; С++ — в разработке интернет-приложений. Механизм исполнения Java делает программы полностью портируемыми, по принципу «написано один раз — запускается везде (write once — run everywhere)», хотя это не было первостепенной целью разработчиков. Стандартное окружение и среда исполнения позволяют выполнять программы на Java на любой аппаратной платформе и в любой ОС без каких-либо изменений, при условии существования на данной ОС и платформе среды исполнения. Усилия по портированию программ минимальны, и могут быть сведены к нулю соблюдением определённых рекомендаций при разработке. Ценой портируемости в данном случае становятся определённые накладные расходы (например, размер среды исполнения Java превышает даже их размеры у всех функциональных языков).

Парадигма программирования

Java в значительно более высокой степени, чем С++, отвечает фундаментальному принципу ООП «всё — объект» (но не в абсолютной — методы классов самостоятельными объектами не являются, в отличие от CLOS или Python). Для объявления глобальных функций или переменных в Java их необходимо оборачивать в фиктивные классы и назначать свойство статичности[37]. Для задания главной функции даже самой простой программы на Java необходимо поместить её в класс[38]. Программировать на Java в функциональном стиле затруднено[источник?], поскольку на уровне синтаксиса языка нет поддержки основных элементов ФП (таких как функций высшего порядка) и нет средств макрорасширения языка.

Объектная модель

Как и в С++, объектная модель Java наследуется из Симулы (в Java — через промежуточную ступень — язык Modula-2), то есть фундаментально отличается от оной в потомках языка Smalltalk (Objective-C, Python, Ruby). Но есть серьёзные отличия и от С++. В Java все методы являются виртуальными. Есть синтаксический сахар для определения абстрактных классов: использование ключевого слова interface делает все методы класса чистыми виртуальными — такие классы называются в Java «интерфейсами». Множественное наследование допустимо только для них, но не для обычных классов, что улучшает дисциплину программирования — на этапе реализации нет возможности нарушить структуру проекта, построенную на этапе архитектурного проектирования (в С++ это делается легко).

Операторы

Безусловный переход в Java отсутствует. Тернарная условная операция в Java также отсутствует. Однако, большинство конструкций являются типичными для всех потомков Алгола: императивный порядок вычислений, присваивания, ветвления, циклы, инфиксные арифметические операции, аргументы в объявлениях и вызовах функций, и пр. В целом спецификация Java отвечает принципу наименьшего удивления и позволяет быстрый переход на Java с любого языка семейства Алгола. Однако, есть и исключения — например, Java, как и C++, позволяет пропускать break в ветви оператора switch[39].

Синтаксис

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

Адресная арифметика

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

Кодогенерация

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

Интроспекция

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

Управление ресурсами

C++ позволяет использовать принцип «захват ресурсов путём инициализации» (RAII), при котором ресурсы ассоциированы с объектом и автоматически освобождаются при разрушении объекта (например, std::vector и std::ifstream). Также возможен подход, когда программист, выделяя ресурсы (память под объекты, открытые файлы и т. п.), обязан явно позаботиться о своевременном их освобождении. Java работает в среде со сборкой мусора, которая автоматически отслеживает прекращение использования объектов и освобождает занимаемую ими память, если в этом есть необходимость, в некоторый неопределённый момент времени. Ручное управление предпочтительнее в системном программировании, где требуется полный контроль над ресурсами, RAII и сборка мусора удобнее в прикладном программировании, поскольку в значительной степени освобождают программиста от необходимости отслеживать момент прекращения использования ресурсов. Сборщик мусора Java требует системных ресурсов, что снижает эффективность выполнения программ, лишает программы на Java детерминированности выполнения и способен следить только за памятью. Файлы, каналы, сокеты, объекты графического интерфейса программист на Java всегда освобождает явно.

Окружение

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

См. также

  • wxWidgets
  • Qt
  • Тернарная условная операция в С++
  • Стандартная библиотека языка Си
  • Стандартная библиотека языка C++

Примечания

↑ Показывать компактно

  1. Шилдт, 1998, с. 57
  2. Страуструп, 1999, 2.1. Что такое C++?, с. 57
  3. Стэнли Липпман, Pure C++: Hello, C++/CLI (англ.)
  4. ↑ Jump up to: 12 Страуструп, 1999, 1.4. Исторические замечания, с. 46
  5. C++ — Standards
  6. Bjarne Stroustrup. C++ Glossary. Проверено 8 июня 2007. Архивировано из первоисточника 27 мая 2012.
  7. ↑ Jump up to: 12 Страуструп, Дизайн и эволюция C++, 2007
  8. Страуструп, 1999, 1.6
  9. ISO/IEC 14882:1998, раздел 6.4, пункт 4: «The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variable implicitly converted to bool … The value of a condition that is an expression is the value of the expression, implicitly converted to bool for statements other than switch; if that conversion is ill-formed, the program is ill-formed».
  10. STLport: Welcome!
  11. Интервью Б. Страуструпа LinuxWorld.com
  12. Интервью Б. Страуструпа журналу «Системный администратор»
  13. CNews: Эксклюзивное интервью с создателем языка программирования C++
  14. ↑ Jump up to: 12 Alan Kay's Definition Of Object Oriented Programming. Архивировано из первоисточника 13 августа 2013.
  15. ↑ Jump up to: 123 Mаrtin Ward Language Oriented Programming. — Computer Science Department, Science Labs, 1994.
  16. Paul Hudak Modular Domain Specific Languages and Tools. — Department of Computer Science, Yale University.
  17. Андрей Карпов 20 ловушек переноса Си++ - кода на 64-битную платформу. — RSDN Magazine #1-2007, 25.04.2007.
  18. Ian Joyner A Critique of C++ and Programming and Language Trends of the 1990s - 3rd Edition. — копирайт и список изданий.
  19. В качестве контр-примеров можно рассмотреть синтаксис нескольких языков, семантически намного более мощных, чем С++:

o

      • определение минимального ядра языка Lisp (относимого к метаязыкам) представляет собой всего 7 конструкций, его реализация на самом Лиспе занимает всего 15 строк кода (хотя в таком варианте Лисп мало применим в промышленности); стандарт R6RS диалекта Scheme содержит 23 строки РБНФ (из которых 11 являются лишь «синтаксическим сахаром»); при этом «код» и «данные» в Лиспе определяются и используются единообразно — за счёт этого рефлексивное метапрограммирование оказывается рутинным делом.
      • ядро Форта (также относимого к метаязыкам) реализуется за день на Ассемблере; простейший интерпретатор Тьюринг-полного языка — семантического аналога Форта (не эффективного и не предназначенного для реального использования во встраиваемых системах — см. игрушечный язык программирования), реализуется за считанные минуты на многих ЯВУ.
      • компилятор минимального подмножества языка OCaml на нём самом занимает всего порядка пятисот строк кода.
  1. Walid Taha Domain-Specific Languages. — Department of Computer Science, Rice University.
  2. Lugovsky V.S. Using a hierarchy of Domain Specific Languages in complex software systems design. — 2008.
  3. Страуструп, Программирование: принципы и практика использования C++, 2001
  4. Dave Gottner. Templates Without Code Bloat. — Dr. Dobb's Journal, январь 1995.
  5. Adrian Stone. Minimizing Code Bloat: Redundant Template Instantiation. Game Angst (22 сентября 2009). Проверено 19 января 2010. Архивировано из первоисточника 27 мая 2012.
  6. Herb Sutter. C++ Conformance Roundup. — Dr. Dobb's Journal, январь 2001.
  7. Are there any compilers that implement all of this?. comp.std.c++ frequently asked questions / The C++ language. Comeau Computing (англ.) (10 декабря 2008). Проверено 19 января 2010. Архивировано из первоисточника 27 мая 2012.
  8. Scott Meyers. Code Bloat due to Templates. comp.lang.c++.moderated. Usenet (16 мая 2002). Проверено 19 января 2010.
  9. ↑ Jump up to: 123 Ray Tracer Language Comparison (бенчмарк языков программирования — ffconsultancy.com/languages/ray_tracer/)
  10. Boehm H. Advantages and Disadvantages of Conservative Garbage Collection.
    (ссылка изРеймонд, Эрик. Искусство программирования для Unix.. — 2005. — С. 357. — 544 с. — ISBN 5-8459-0791-8)
  11. Don Clugston, CSG Solar Pty Ltd (Перевод: Денис Буличенко) Указатели на функции-члены и реализация самых быстрых делегатов на С++. — RSDN Magazine #6-2004.
  12. Шилдт, Теория и практика С++, 1996, с. 64-67
  13. Эрик Реймонд Искусство программирования для Unix = en:The Art of Unix. — Издательский дом "Вильямс", 2005. — ISBN 5-8459-0791-8
  14. Чистяков Влад aka VladD2 Синтаксический сахар или C++ vs. Nemerle :) // RSDN Magazine #1-2006. — 24.05.2006.
  15. Zhanyong Wan, Walid Taha. Архивировано из первоисточника 13 августа 2013., and Paul Hudak Event-Driven FRP // Department of Computer Science, Yale University.
  16. MLKit. Архивировано из первоисточника 1 августа 2013.
  17. 1.2 Design Goals of the Java™ Programming Language. Oracle (1 января 1999). Проверено 14 января 2013.
  18. Class Arrays, JavaTM 2 Platform Std. Ed. v1.4.2
  19. The Java Tutorials. A Closer Look at the «Hello World!» Application
  20. The Java Tutorials: The switch Statement

Мнения



Последнее изменение этой страницы: 2016-12-12; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.206.177.17 (0.018 с.)