
- •История
- •Развитие и стандартизация языка
- •Совместимость с языком с
- •Обзор языка
- •Полиморфизм
- •Инкапсуляция
- •Конструкторы и деструкторы
- •Средства c, которых рекомендуется избегать
- •Пример № 5
- •Достоинства
- •Критика
- •Синтаксис
- •Ограниченность возможностей
- •Избыточные и опасные возможности
- •Вычислительная производительность
- •Результативность
- •Влияние и альтернативы
Пример № 5
Популярные библиотеки boost в сочетании со стандартными средствами языка позволяют очень лаконично и наглядно записывать код. В приведённом ниже примере вычисляется скалярное произведение векторов нечётных чисел и квадратов. В коде вектора значений представлены ленивыми STL-подобными последовательностями.
#include <iostream>
#include <numeric>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
int odd(int i)
{
return 2 * i + 1;
}
int square(int i)
{
return i * i;
}
typedef boost::counting_iterator <int> counter;
typedef boost::transform_iterator <int (*)(int), counter> transformer;
transformer odds(int n)
{
return transformer(counter(n), odd);
}
transformer squares(int n)
{
return transformer(counter(n), square);
}
int main()
{
using namespace std;
cout << "Enter vector length: ";
int n; cin >> n;
cout << inner_product( odds(0), odds(n), squares(0), 0 ) << endl;
}
Данный пример демонстрирует так называемый «плоский» стиль записи. Это название связано с тем, что алгоритмы STL позволяют записывать код без циклов, соответственно ширина отступов в отформатированном коде примерно постоянна. Сторонники такого подхода считают, что программисту, знакомому со стандартной библиотекой С++, достаточно строчки с вызовом inner_product(), чтобы понять, что делает программа. С этой точки зрения вызов inner_product близок к словесному описанию задачи: «вычислить скалярное произведение векторов нечётных чисел и квадратов для значений от нуля до n».
Достоинства языка и его критика
Особенности
С одной стороны, С++ является потомком Симулы, которую Алан Кэй определил[14] как «Алгол с классами», и потому будет актуальной оценка С++ в сравнении с другими языками из семейства потомков Алгола (Basic, Pascal, Java, C#, Visual Basic, Delphi, D, Oberon и пр.). С другой стороны, С++ претендует на мультипарадигменность и универсальную применимость (в отличие от Си, ориентированного на очень узкий круг задач), и используется в промышленности намного шире других потомков Алгола, и потому будет актуальной оценка С++ в сравнении со всем многообразием применяемых языков, включая и Си. Во избежание повторений, оценки обычно совмещаются.
С++ — язык, складывающийся эволюционно. В отличие от языков с формальным определением семантики (см. Спецификация языков программирования), каждый элемент С++ заимствовался из других языков отдельно и независимо от остальных элементов (ничто из предложенного С++ за всю историю его развития не было новшеством в Computer Science), что сделало язык чрезвычайно сложным, со множеством дублирующихся и взаимно противоречивых элементов, блоки которых основаны на разных формальных базах. В этом отношении С++ повторяет путь PL/1, но, в отличие от последнего, длительное повсеместное использование С++ обеспечил выбор языка Си в качестве отправной точки.
Критики С++ не противопоставляют ему какой-либо конкретный язык, а наоборот, утверждают, что для всякого случая применения С++ всегда существует альтернативный инструментарий, позволяющий решить ту же задачу более эффективно и качественно. В свою очередь, сторонники С++ считают некорректным сравнивать различные аспекты С++ с совершенно различными языками, так как общий набор средств и возможностей С++ существенно шире, чем в большинстве языков, с которыми проводится сравнение, и сама по себе широта возможностей, на их взгляд, является веским оправданием несовершенства каждой отдельно взятой возможности. Более того, по их мнению, высокая совместимость с Си является одной из принципиальных черт языка, и потому все недостатки С++ оправданы преимуществами, предоставляемыми этой совместимостью (см. раздел Философия C++). При этом сторонники C++ игнорируют подтверждённый исследованиями[15][16] факт, что декомпозиция проекта на несколько разных языков, наиболее пригодных для своих мини-задач, (или просто использование одного наилучшим образом подходящего языка) сокращает на порядок общую трудоёмкость разработки при одновременном повышении на порядки основных показателей качества программирования. По этой причине критики не соглашаются рассматривать недостатки С++ по отдельности и тем более делать поправку на «универсальность», утверждая, что если задача требует одновременно высокоуровневых и низкоуровневых возможностей, то использование Си совместно с языками, из которых заимствованы отсутствующие в Си возможности C++, будет более разумным, чем внедрение этих возможностей в сам Си и использование полученного языка резко возросшей степени внутренней сложности.
Таким образом, одно и то же свойство языка (совмещение большого числа элементов разных языков и отсутствие конкретной целевой ниши применения) рассматривается сторонниками как «главное достоинство», а критиками — как «главный недостаток».
Следует отметить, что рассмотрение элементов языка по отдельности означает отказ от рассмотрения языка как системы, а следовательно, и от ожидания синергизма,— что делает ограниченным (конечным) потенциал роста сложности абстракций, которые можно выразить посредством этого языка, и соответственно сужает спектр реализуемых на нём программных систем.
С++ заявляется как кроссплатформенный: стандарт языка накладывает минимальные требования на ЭВМ для запуска скомпилированных программ. На практике, для написания портируемого кода на С++ требуется огромное мастерство и опыт, и «небрежные» коды на С++ с высокой вероятностью могут оказаться непортируемыми[17]. Тонкое владение С++ в принципе может сделать код на С++ столь же портируемым, что и код на Си (хотя, по мнению Линуса Торвальдса, С++ при этом фактически сократится до своего подмножества Си[мнения 3]). Однако, критики С++ утверждают, что изучение и использование одновременно всех языков, противопоставляемых С++ (не вызывающих серьёзных проблем при портировании), в сумме требует примерно тех же интеллекта, усилий и временных затрат, что и изучение и использование одного только С++ на высококлассном уровне — в связи с чем становится актуальной также оценка порога вхождения и результативности (производительности и качества труда программистов).
Многие аспекты в спорах «за и против С++» обусловлены расхождением в сущностном понимании процесса стандартизации. Б.Страуструп и его последователи считают, что «стандарт — это контракт между программистами, разрабатывающими программы на языке, и программистами, разрабатывающими компиляторы языка»[7]. Каждый новый стандарт С++ являлся декларацией того, что отныне должно быть реализовано во всех компиляторах — при том, что С++ имеет естественное определение семантики, то есть потенциально зависим от реализации (стандарт содержит множество пунктов, определённых как «implementation-defined»). Традиционно, успешная стандартизация в технике представляет собой формальный перевод стандарта из статуса де-факто в статус де-юре (подытоживание общепринятых, устоявшихся знаний для обеспечения надёжной внутриотраслевой совместимости). Все противопоставляемые С++ языки программирования, если проходили процедуру стандартизации (что не обязательно для портируемости), то лишь после многолетней апробации на практике; при этом все они изначально имеют формальное определение семантики, так что накапливающиеся к моменту стандартизации изменения от первой версии языка оказываются не принципиальны. Теоретически эти определения стандартизации тождественны. На практике определение Страуструпа согласуется с традиционным лишь при условии, что нет абсолютно никаких препятствий против немедленного и беспрекословного подчинения статуса де-факто декларированному де-юре — то есть если абсолютно все компиляторы реализуют поддержку нового стандарта сразу после его выхода и со 100 % соответствием ему, и что новый стандарт не отменяет никаких положений старого, кроме признанных убыточными или вредоносными. Так может происходить лишь в условиях полного отсутствия человеческого фактора (иначе говоря, при отсутствии программистов как таковых). На практике именно этим и обусловлено значительное отставание реальной кроссплатформенности С++ от заявленной разработчиками стандарта и противоречивость предлагаемых возможностей. Сторонники С++ считают взгляд Страуструпа на стандартизацию более практико-ориентированным и принимают порождаемые им проблемы за должное.