LINUX.ORG.RU

Производительность C++

 ,


7

13

Как насчёт производительности у C++ по сравнению с C? Мои предположения на текущий момент:

1) Код, не использующий возможности C++ (то есть по сути plain C), скомпилированный C++ компилятором будет иметь абсолютно ту же производительность, что и код на С.

2) Исключения и dynamic_cast медленные. Если нам важна производительность, лучше их не использовать.

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

4) Класс с виртуальными методами полностью аналогичен пункту 3, но при вызове виртуальных методов добавляется небольшой оверхед. Сишный эквивалент obj->vtable->func(obj, ...). Если сравнивать с plain C кодом, реализующим ООП в той же манере (каждая структура-объект имеет поле, указывающее на структуру, содержащую адреса функций работы с ней), то оверхеда по сравнению с plain C не должно быть.

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

6) Шаблоны могут привести к разбуханию кода. Впрочем, #define-ы и inline-функции в C++ могут устроить то же самое. Вопрос: будет ли использование шаблона с одинаковыми параметрами создавать 2 копии реализации или же всё-таки компилятор догадается сделать её лишь один раз. А если шаблон используется с одинаковыми параметрами в нескольких объектных файлах? Будет ли реализация расшариваться между ними или у каждого своя?

7) Что насчёт inline-методов класса? (те, которые описываются прямо в момент определения самого класса, внутри блока class). Может ли их реализация расшариваться между модулями или в каждом будет своя копия (допустим, метод слишком длинный, чтобы инлайнится в момент вызова)?

Я не претендую на правоту, какие-то утверждения могут быть ложными. Хотел бы узнать, как обстоят дела на самом деле. А также какие подводные камни я ещё не знаю. Разумеется, речь идёт о последних версиях gcc/clang с включённой оптимизацией не ниже -O2.

★★★★★

Последнее исправление: KivApple (всего исправлений: 1)

Тред не читал. Про deep copy уже вспоминали? В сишечке такой засады не было, имхо.

anonymous
()
Ответ на: комментарий от eao197

В 85-м вышла первая коммерческая версия. И что?

Одновременно с первой версией вышло и первое издание книги «Язык программирования C++», только после этого о языке стало известно более-менее широкой публике.

Хорошо, не будем держаться за 83 и даже за 85 год. В 87 году в состав gcc попал g++ ( см. http://progopedia.ru/implementation/gpp/ ), т. е. официальная гнутая версия c++. Кстати, хоть первая версия gcc (включавшая только си) была написана в 85 году, но официальный гнутый статус он получил в том же 87. Т. е. g++ включалась в gcc уже с самой первой версии и через 2 года после основания FSF. А с 90-ого года (т. е. ещё до появления Linux) существовал популярный некогда turbo c++ для писюх. В 93 (уже через 2 года после появления первой версии ядра Linux) появился 32-битный watcom c++. Но всё это в свете проекта GNU вообще и Linux'а в частности неважно, т. к. с 87 г. существовал gcc, уже тогда включавший в себя g++.

А большинство unix-утилит и не являются системными. Это не ядро.

Зато им нужна переносимость на большое количество платформ.

Мы уже поняли, что g++ существовал с 87 года, а именно на gcc писался весь софт в рамках проекта FSF и ядро Linux.

А Qt до сих пор компилируется moc'ом в си++. И кому это мешает?

И кто-то использует Qt для реал-тайма или хардкорной системщины?

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

В начале по поводу C++ у многих были подозрения о том, насколько он эффективен в сравнении с C. Потребовалось довольно много времени, [skip] чтобы убедительно доказать, что существенного разрыва между C и C++ нет.

Для доказательства этого факта достаточно откомпилировать си и си++ программы и сравнить производительность. Сделать это можно за неделю, да и то если проводить довольно тщательные тесты по всем направлениям. А просто примерно оценить производительность можно за день.

Уровни поддержки C++ в компиляторах начала 1990-х, особенно для x86, — это вообще пестня. Так что ничего не удивительного, что тогда Торвальдс не стал связываться с тогдашним C++.

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

А фортран появился задолго до си и до этих ваших юниксов.

На Fortran-е ядра для Unix-ов не писали. И системные утилиты для Unix-ов не писали. А на C писали.

Правильно. Потому что си был создан именно для написания на нём Unix. Т. е. он появился именно с этой целью, и в тот момент, когда Unix начали переписывать на нём, действительно никто, кроме сотрудников Bell Labs и, возможно, нескольких их знакомых, даже не знал о существовании этого языка. Ни о каком, даже самом скромном сообществе и речи не было. Си начал распространяться одновременно и вместе с Unix. В то время как Fortran был старейшим языком высокого уровня и всё ещё очень популярным в то время. Но это не помешало си стать системным языком высокого уровня. Т. е. не всё определяется традициями. Если появляется новый востребованный инструмент, предоставляющий новые возможности, то традиции легко ломаются. И для этого нет необходимости ждать 10 или более лет. А вот если новый прекрасный язык не способен в полной мере заменить старые, - значит не так уж он и прекрасен, как кажется его апологетам.

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

aureliano15 ★★
()
Ответ на: комментарий от AlexVR

простота отладки.

Всё проще. Есть Си с его соглашением о вызове cdecl и отделением котлет от мух (данных от функций). И это легко воспроизводимо в других языках программирования. Много ли ты знаешь ЯП не умеющих работать с Си-шными библиотеками?

И это тоже. Но всё-таки это достоинство больше касается написания библиотек и внешних интерфейсов и не объясняет, почему и внутренние функции ядра (не предназначенные для взаимодействия с юзерспэйсом), а также различные автономные утилиты командной строки написаны на си без крестов. Кроме того, если библиотека очень удачная, си++-реализация не является помехой для портирования. Взять ту же Qt, написанную на си++ и PyQt для питона.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

В 87 году в состав gcc попал g++
Мы уже поняли, что g++ существовал с 87 года, а именно на gcc писался весь софт в рамках проекта FSF и ядро Linux.

Это вы о себе говорите «мы»? Повторюсь, вы живете в мире каких-то розовых пони. Если g++ включили в состав gcc, значит это была какая-то супер-пупер реализация самой актуальной версии C++ на тот момент... Блин, да вы идеалист.

Мне вот, в начале 2000-х довелось столкнуться с версией g++, которая не могла ловить исключение по ссылке на базовый класс. Кидаешь Derived, по ссылке на Derived ловит, по ссылке на Base — нет.

Это, блин, начало 2000-х, уже С++98 официальный стандарт, часть его фич даже в VC++6.0 поддерживается. А тут такое.

Про реал-тайм мы пока вообще не говорили, а что касается системщины, то графическая библиотека в принципе для этого не предназначена.

Так с какого перепугу вы Qt в пример приводите?

Мне кажется, что корень проблемы надо искать здесь, а не в недостаточной стандартизации си++ начала 90-ых.

Ну перекреститесь, если вам что-то кажется.

Повторюсь: в начале 90-х выбор в пользу чистого C вместо C++ в тогдашнем состоянии C++ и средств разработки для него, был вполне себе оправдан. Даже если не брать в расчет то, что имевшиеся тогда в наличии открытые и не очень ядра Unix-подобных ОС были написаны как раз на C.

В то время как Fortran был старейшим языком высокого уровня и всё ещё очень популярным в то время. Но это не помешало си стать системным языком высокого уровня.

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

И причину надо искать не в том, что де традиция такая

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

Добавим сюда и простую человеческую глупость. Например, Торвальдс высказался о C++ больше 20 лет назад, да еще и про C++ в очень узкой нише и в очень специфических условиях (OpenSource, отсутствие дедлайнов и пр. отличия от коммерческой разработки). Но, блин, до сих пор этот аргумент притаскивают за уши, даже не удосуживаясь подумать об его актуальности в наше время и в каких-то других условиях.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

Первая версия gcc была написана на паскале, что не помешало полностью переписать её через 2 года на си. Когда-то давно я читал (не готов ручаться, что это так, но за что купил, за то и продаю), что первые версии Windows тоже были написаны на паскале, откуда, якобы, и соглашение PASCAL, впоследсвии переделанное в STDCALL для API Windows. Но это тоже не помешало в какой-то момент переписать её на си. Во время дрязг с AT&T Berkeley полностью избавился от проприетарного, хоть и открытого кода AT&T, переписав его с нуля для своей BSD. Да и сейчас такое часто случается по самым разным причинам (от проблем с копирайтами до желания сделать программу более переносимой/эффективной и т. д.) Поэтому легаси и традиции хоть и тянут назад, но не являются непреодолимым препятствием, если новая технология даёт действительно серьёзные преимущества, в разы перевешивающие недостатки.

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

Добавим сюда и простую человеческую глупость. Например, Торвальдс высказался о C++ больше 20 лет назад, да еще и про C++ в очень узкой нише и в очень специфических условиях (OpenSource

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

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Я вот, честно, не понимаю, что вы пытаетесь сказать.

Ну да, Windows 1.0, которая была даже не ОС, а просто GUI над MS-DOS-ом, начали писать на PASCAL-е. Потом убедились, что для подобных вещей C лучше и начали делать на C. При разработке Windows NT убедились, что на C++ делать это еще лучше и стали использовать C++ (покоцанный, но все-таки).

И?

Есть и фундаментальные объективные причины.

Большинство этих причин мы с вами выше уже обсудили (точнее, я вам о них уже рассказал). Еще одна — это поветрие, что C проще в изучении и использовании. Поэтому отдельные дятлы (которые при этом в разы, а то и на порядки умнее меня) в XXI-ом веке берутся говнокодить на чистом C, да еще там, где найти плюсы такого решения совсем не просто (один из примеров в соседней теме сейчас обсуждается). Как найти этому какое-то логическое объяснение — не знаю. Вероятно, у людей голова другими вещами забита, time-to-market matters и все такое. Отсюда и фигак-фигак-и-в-продакшен, вместо написания нормального кода.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Отсюда и фигак-фигак-и-в-продакшен, вместо написания нормального кода.

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

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Это была как раз реал-тайм система.

Это было мнение одного конкретного разработчика со своими тараканами в голове. Систем реального времени на C++ сделано немало. И, во многих случаях, там противоположная точка зрения: никакого plain old C и прочего г.

eao197 ★★★★★
()
Ответ на: комментарий от aureliano15

Потому что си был создан именно для написания на нём Unix. Т. е. он появился именно с этой целью, ... Си начал распространяться одновременно и вместе с Unix. В то время как Fortran был старейшим языком высокого уровня и всё ещё очень популярным в то время. Но это не помешало си стать системным языком высокого уровня. Т. е. не всё определяется традициями.

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

grem ★★★★★
()
Ответ на: комментарий от grem

Си начал распространяться одновременно и вместе с Unix. В то время как Fortran был старейшим языком высокого уровня и всё ещё очень популярным

Fortran создали и развивали не для написания OS, поэтому никакой конкуренции в этом плане C он никогда мог составить.

Так и я о том же. Вот конец процитированного абзаца:

Т. е. не всё определяется традициями. Если появляется новый востребованный инструмент, предоставляющий новые возможности, то традиции легко ломаются. И для этого нет необходимости ждать 10 или более лет. А вот если новый прекрасный язык не способен в полной мере заменить старые, - значит не так уж он и прекрасен, как кажется его апологетам.

Со своей задачей Fortran до сих пор справляется не хуже C, а местами даже лучше

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

Впрочем, ничего удивительного в этом нет: фортран - первый язык высокого уровня, первый блин, так сказать. Насколько я помню (смотрел когда-то давно), в if там было 3 условия с переходами по меткам, а вместо явных описаний типы определялись по первой букве. И, по-моему, не было структур. В таком виде язык не мог выиграть конкурентную борьбу с более новыми языками. Но он был первым. Возможно, в современном фортране всё не так, - не знаю.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

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

смотря в какой области: https://en.wikipedia.org/wiki/List_of_quantum_chemistry_and_solid-state_physi...

Насколько я помню (смотрел когда-то давно), в if там было 3 условия с переходами по меткам, а вместо явных описаний типы определялись по первой букве. И, по-моему, не было структур. В таком виде язык не мог выиграть конкурентную борьбу с более новыми языками. Но он был первым. Возможно, в современном фортране всё не так, - не знаю.

Всё давно не так, он тоже не остановился на Fortran 66 и 77.

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

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)
Ответ на: комментарий от grem

смотря в какой области: https://en.wikipedia.org/wiki/List_of_quantum_chemistry_and_solid-state_physi...

Да, список впечатляет. Даже не ожидал.

есть свои вкусняшки, особенно в плане работы с многомерными массивами, их срезами (включая строки).

Спасибо за инфу.

Ну и увеличение размера динамического массива с сохранением данных пока что выполняется в 3 действия с созданием ещё одного для промежуточного хранения данных.

А зачем так сложно? Не проще ли в 2 действия (пишу в синтаксисе си++):

arr2=new char[new_size];
memcpy(arr2, arr1, old_size);

Я догадываюсь, что на фортране это может записываться по-другому, но сам принцип: выделяем динамическую память и копируем в неё старые данные. Потом старый массив можно удалить, если он не нужен. Но зачем 3-й промежуточный массив?

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Да, всё так. Массив промежуточный один, три действия: выделение памяти для временного массива новой размерности; копирование данных во временный массив из исходного; «перенос указателя» со старого на адрес временного массива, с автоматическим «удалением привязки» имени временного к этому же адресу (если это так описывается).

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

grem ★★★★★
()
Ответ на: комментарий от grem

Но можно и в две строки, указав, какими данными из исходного заполнить временный массив при выделении памяти. Только всё это появилось в стандарте 2003 года.

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

aureliano15 ★★
()
Ответ на: комментарий от RazrFalcon

Генерирует доп. файл

Ну, это уже детали реализации. Главное, что из Qt-кода генерируется C++-код. А Cfront генерировал из си++-кода чистый си-код.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Главное, что из Qt-кода генерируется C++-код.

Нет. Нет никакого Qt кода. cpp/h с Qt собираются обычным компилятором, без модификаций.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Нет никакого Qt кода. cpp/h с Qt собираются обычным компилятором, без модификаций.

Но для сборки необходим

доп. файл с сигналами, слотами и рефлексией

генерируемый moc'ом.

aureliano15 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.