Поэтому утверждение о том, что С и С++ почти всегда являются неподходящим связующим материалом для начала разработки новых приложений, может показаться неверным. Тем не менее, оно справедливо. С и С++ оптимизируют машинную эффективность ценой увеличения времени реализации и (особенно) отладки. Несмотря на то, что писать на С или С++ системные программы и чувствительные ко времени выполнения ядра приложений все еще имеет смысл, мир значительно изменился со времен возвышения этих языков в 1980-х годах. Сегодня процессоры в тысячи раз быстрее, модули памяти в тысячи раз больше, а диски в десять тысяч раз больше, причем примерно по тем же ценам [118] За пределами мира Unix этот прирост аппаратной производительности на три порядка в значительной мере затмевается соответствующим понижением производительности программ.
.
Падение цен фундаментально изменило экономику программирования. В большинстве обстоятельств уже не имеет смысла так экономить аппаратные ресурсы, как это позволяет С. Напротив, экономически оптимальный выбор состоит в минимизации времени отладки и максимизации возможности долгосрочного сопровождения кода. Следовательно, большинство видов реализации (включая создание прототипов приложений) лучше обслуживаются более новым поколением интерпретируемых языков и языков сценариев. Эта трансформация точно соответствует тем условиям, которые на предыдущем витке исторической спирали привели к восхождению C/C++ и снизили важность программирования на ассемблере.
Центральной проблемой С и С++ является то, что они требуют от программистов самостоятельно осуществлять управление памятью — объявлять переменные, явно управлять связными списками, определять размеры буферов, обнаруживать или предотвращать переполнение буферов, а также распределять и высвобождать динамическую память. Некоторые из указанных задач могут быть автоматизированы путем искусственных действий, таких как дополнение С программой сборки мусора, например, реализация Boehm-Weiser, однако конструкция С такова, что подобное решение не может быть совершенным.
Управление памятью в С — серьезный источник трудностей и ошибок. По оценкам одного исследования (цитата из [9]), 30 или 40% времени разработки отводится на управление памятью в программах, которые манипулируют сложными структурами данных. В это число даже не включаются затраты на отладку. Несмотря на отсутствие точных данных, многие опытные программисты уверены, что ошибки управления памятью являются единственным крупнейшим источником постоянных ошибок в реальном коде [119] Серьезность данной проблемы подтверждается богатым сленгом, выработанным Unix-программистами для описания различных ее разновидностей: "псевдонимная ошибка" (aliasing bug), "нарушение выделенной области памяти" (arena corruption), "утечка памяти" (memory leak), "переполнение буфера" (buffer overflow), "разрушение стека" (stack smash), "отклонение указателя" (fandango on core), "недействительный указатель" (stale pointer), "подкачка памяти" (heap trashing), а также вызывающее справедливые опасения "вторичное повреждение" (secondary damage). Пояснения приведены в Словаре хакера .
. Переполнение буфера является обычной причиной аварий и брешей в системе безопасности. Управление динамической памятью особенно чревато порождением коварных и трудно отслеживаемых ошибок, таких как утечки памяти и проблемы недействительного указателя.
Вместе с тем не так давно ручное управление памятью имело смысл. Однако теперь "малых систем" больше нет, а в передовом программировании приложений ручное управление памятью не требуется. В современных условиях гораздо более целесообразно использовать язык реализации, который автоматизирует управление памятью (и на порядок сокращает количество ошибок ценой использования несколько большего числа циклов и памяти).
В недавней статье [63] собран впечатляющий массив статистических данных в пользу заявления, которое опытные программисты сочтут весьма правдоподобным: продуктивность программистов при работе с языками сценариев почти в два раза больше продуктивности при работе с С или С++. Данное утверждение хорошо согласуется с приведенной выше оценкой затрат времени (30-40%), а ведь еще следует учесть издержки отладки. Потери производительности при использовании какого-либо языка сценариев очень часто незначительны для реальных программ, поскольку такие программы склонны ограничиваться ожиданием I/O-событий, сетевой задержки и заполнением кэша, а не эффективностью, с которой они используют сам процессор.
Читать дальше