Re: Велоспорт вчера, сегодня, завтра, ...
От: McSeem2 США http://www.antigrain.com
Дата: 26.04.05 00:22
Оценка: +1
Несколько замечаний.

SDB>Карандашом на полях. Мне было бы очень интересно узнать, кто пустил миф о том, что "программы на C++ медленнее, чем программы на C". Нет, формально я понимаю, что тот же виртуальный вызов будет выполняться дольше (на несколько тактов) просто в силу большего количества инструкций — но я не ощущал этой разницы даже на 286-х.


В стародавние времена, когда компиляторы C++ были весьма сырыми, это было действительно так. Но не столько из за самого C++, а из за спонтанно возникшей моды на полиморфизм везде и всюду. А так же на тенденцию к попыткам объять необъятное — казалось, что C++ этому способствует. В результате классы становились настолько толстыми и неуклюжими, что действительно возникали значительные накладные расходы. Это во-первых. Во-вторых, слабая оптимизация. Как раз на 286-х мы сделали простеший класс для комплексной арифметики. Все в соответствии с классическими канонами. Так вот, сложные выражения, переписанные один-в-один с Фортрана, работали раз в 10 медленнее, чем на самом Фортнане. Чисто из за накладных расходов на копирование. При этом, если то же самое выражение разложить на простую вещественную арифметику (застрелиться можно), то скорость выравнивалась. Спрашивется, кому он нужен такой язык, если даже комплексная арифметика на нем толком не идет
В третьих, программы на C++ были действительно медленнее, чем на C по той простой причине, что C заставляет тщательнее прорабатывать детали в силу своей более хакерской направленности и атмосферы.

Что же касается виртуальных вызовов, то это все зависит от области применения. ..."но я не ощущал этой разницы даже на 286-х" — это не значит, что ее нет. Просто не было таких задач, где она была бы заметна.

Современный же C++, с его метапрограммированием, как раз позволяет значительно лучше оптимизировать по скорости, чем старый C. Типичный пример — CRT qsort, в которой выполняются миллиарды обратных вызовов функции сравнения. Для сортировки целых чисел это становиься весьма критичным и может замедлить работу в несколько раз по сравнению с вариантом с прямыми сравнениями (извиняюсь за тавтологию). Именно поэтому, для наиболее критичных случаев, я писал свой велосипед в виде узкоспециализированной сортировки, без каких либо вызовов. Теперь у нас есть std::sort(), в которой никаких дополнительных вызовов может и не быть (но если хочется — будут).

SDB>Очень серьезный удар по велосипедистам нанес Комитет, узаконивший в 1998-м году STL как часть языка. К сожалению (или все-таки к счастью?) Окна несколько смягчили его: стандартные (теперь уже без кавычек) контейнеры оказались (что естественно) "далеки от народа" — то есть, от Windows API. MFC, ставшая стандартом де-факто для разработки Windows-приложений, содержала собственный набор, который, с одной стороны, уже стал привычным, а с другой — мог практически без всякой головной боли использоваться с прямыми API-шными вызовами.


Вот именно, что MFC — это не просто библиотека, а библиотека, заточена на конкретный низкоуровневый API. Заточенная плохо, в силу плохой совместимости низкоуровневого API и C++ в общем и целом.

SDB>Посмотрим на простой пример:

SDB>CString strExeName;

SDB>::GetModuleFileName(AfxGetInstanceHandle(), strExeName.GetBuffer(_MAX_PATH), _MAX_PATH);
SDB>strExeName.ReleaseBuffer();

SDB>К сожалению, написание аналогичного кода с использованием std::string потребует промежуточной переменной.

Ну это не аргумент. На самом деле, это лишь полумера и незначительная автоматизация. Взамен дополнительного буфера возникает необходимость вызывать какую-то невнятную ReleaseBuffer() и это все портит. Это как раз иллюстрирует проблему несовместимости C++ и низкоуровневого API — добавлена некая "примочка" к классу, вроде как стало лучше, но все равно как-то коряво. То же самое:

char buf[_MAX_PATH];
::GetModuleFileName(AfxGetInstanceHandle(), buf, _MAX_PATH);

std::string strExeName = buf;


Те же самые три строки. Но да, дополнительный буфер взамен необходимости соблюдения некого "протокола" (ведь GetBuffer/ReleaseBuffer — это уже stateful protocol).

Гораздо более серьезная проблема совместимости C++ с API — это семантика обратных вызовов без указания объекта-владельца. То самое пресловутое — как мне привязать объект класса к WindowProc. Вот уж где приходится огород городить иногда.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.