Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.
Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
Интересно как дело обстоит когда мы используем только наследование?
Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?
Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Интересно как дело обстоит когда мы используем только наследование? K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?
#include <stdio.h>
class Base
{
public:
Base() : add_(123)
{
}
int add(int x, int y)
{
return x + y + add_;
}
protected:
int add_;
};
class Test : public Base
{
};
int main(int argc, char *argv[])
{
printf("%d\n", Test().add(1, 2));
return 0;
}
Наверно это компилятор С++ оптимизировал так код, что даже числа сам сложил!
А в целом логично что методы классов ничем не отличаются от обычных функций, а поля от глобальных переменных. Вообщем этого я и ожидал.
Re: Скорость работы с использованием классов и без
Kokoban wrote: > Типичное мнение старых С-программистов — то, что использование С++ > классов тормозит работу программы.
Не надо слушать таких программистов.
Во-первых, значительную часть виртуальных вызовов компилятор
замечательно соптимизирует в статические.
Во-вторых, в новых процессорах есть специальные аппаратные оптимизации
косвенного вызова.
В-третьих, можно замечательно использовать ООП без виртуальных функций.
В качестве примера можно взять STL.
> Понятно, что использование таблиц виртуальных функций влияет на > производительность программ, но как сильно?
Очень незначительно.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы. K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
Сравнивать языки есть смысл только на общем подмножестве конструкций языка.
Нету в С виртуальный методов, потому нет смысла сравнивать виртуальные методы в С++
с тем, чего нету в С. Иначе надо сравнивать виртуальные методы в С++
с некой самопольной эмуляцией виртуальных методов средствами голого С.
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.
K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.
Основной проблемой считались не тормоза виртуальных функций, а увеличение объемов программы. Размер почити каждого объекта увеличивается на одно слово в котором хранится указатель на таблицу виртуальных функций. Ну и еще там всякием мелочи. Сейчас память сильно подешевела и этой проблемы вроде как нет.
Скорость больше зависит от того как напишешь, а не на чем.
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы. K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно? K>Интересно как дело обстоит когда мы используем только наследование? K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?
K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.
B>Сравнивать языки есть смысл только на общем подмножестве конструкций языка. B>Нету в С виртуальный методов, потому нет смысла сравнивать виртуальные методы в С++ B>с тем, чего нету в С. Иначе надо сравнивать виртуальные методы в С++ B>с некой самопольной эмуляцией виртуальных методов средствами голого С.
Извините за небольшой offtop:
Аналог виртуальных функций легко реализуется с помощью явного задания таблиц функций.
При этом появляется преимущесто в том, что нет необходимости обязательно реализовывать все "виртуальные" функции.
Например возьмем интерфейс IMalloc, который реализует Alloc,Realloc,Free.
Предположим, что в какой-то его реализации (например ядро Linux) нетривиально написать функцию Realloc.
Что делать клиенту, если перед ним стоит задача увеличить размер буффера?
Сравните:
// виртуальные функции. Realloc обязан быть реализованvoid Func( IMalloc* I )
{
void* p = I->Alloc( 100 );
void* p2 = I->Realloc( p, 200 );
if ( NULL != p2 )
p = p2;
...
}
// таблицы функций. Realloc не обязан быть реализован
// Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULLvoid Func( IMalloc* I )
{
void* p = I->Alloc( 100 );
if ( NULL != I->Realloc )
{
void* p2 = I->Realloc( p, 200 );
if ( NULL != p2 )
p = p2;
}
else
{
void* p2 = I->Alloc( 200 );
if ( NULL != p2 )
{
memcpy( p2, p, 100 );
I->Free( p );
p = p2;
}
}
...
}
Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету.
Попробуйте в C++ виртуальности подменить виртуальную функцию.
Re[3]: Скорость работы с использованием классов и без
Не вопрос, что это все можно реализовывать ручками...
Но, как и любая ручная реализация, это решение будет подвержено ошибкам и будут тратиться усилия на поддержку
всей этой ручной инфраструктуры в нормальном состоянии.
В С++ это делает компилятор...
MS>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету. MS>Попробуйте в C++ виртуальности подменить виртуальную функцию.
У меня видимо не такие задачи как у тебя.
Мне еще ни разу не требовалось подменять виртуальные функции на лету.
Ну либо это решалось какими-то более явными методами.
Re[3]: Скорость работы с использованием классов и без
MShura wrote: > // таблицы функций. Realloc не обязан быть реализован > // Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULL
Можно вопрос? А зачем функции Func знать о том как работает IMalloc?
Если у меня есть только malloc/free, то просто просто в своей реализации
IMalloc делаем его через memcpy+malloc. Если о подробностях работы
IMalloc надо знать клиентскому коду (например, для включения
оптимизаций), то делаем интерфейс IMallocInfo с методом GetReallocCaps.
> Точно также с помощью таблиц легко реализовать подмену "виртуальной" > функции уже на лету. > Попробуйте в C++ виртуальности подменить виртуальную функцию.
Ни разу не было такого желания.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[4]: Скорость работы с использованием классов и без
C>MShura wrote: >> // таблицы функций. Realloc не обязан быть реализован >> // Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULL C>Можно вопрос? А зачем функции Func знать о том как работает IMalloc?
Если IMalloc реализует нужный функционал, то воспользоваться им. Если нет, то воспользоваться другим способом.
C>Если у меня есть только malloc/free, то просто просто в своей реализации C> IMalloc делаем его через memcpy+malloc. Если о подробностях работы C>IMalloc надо знать клиентскому коду (например, для включения C>оптимизаций), то делаем интерфейс IMallocInfo с методом GetReallocCaps.
Как раз самую элементарную информацию о методе (реализован/не реализован) легко получить сравнив с NULL указатель на функцию.
Виртульная файловая система Linux (vfs) очень активно использует тиблицы функций.
Например ваша файловая система может поддерживать открытие файла по некоторому номеру, другая только по имени, третья и по тому и по другому признаку. В каждом случае вы зополняете только необходимые элементы таблицы. vfs анализируя эту таблицу пользуется тем или иным способом.
>> Точно также с помощью таблиц легко реализовать подмену "виртуальной" >> функции уже на лету. >> Попробуйте в C++ виртуальности подменить виртуальную функцию. C>Ни разу не было такого желания.
Элементарный hook какого-нибудь метода стороннего COM объекта
Re[5]: Скорость работы с использованием классов и без
MShura wrote: > C>Можно вопрос? А зачем функции Func знать о том как работает IMalloc? > Если IMalloc реализует нужный функционал, то воспользоваться им. Если > нет, то воспользоваться другим способом.
Просто IMalloc _обязан_ реализовать нужный функционал. Если изначально
планируется возможность, что некоторые функции не будут реализованы — то
пусть возвращают E_NOTIMPL. Пихать NULL в таблицу функций — это уже
извращение.
> C>Если у меня есть только malloc/free, то просто просто в своей реализации > C> IMalloc делаем его через memcpy+malloc. Если о подробностях работы > C>IMalloc надо знать клиентскому коду (например, для включения > C>оптимизаций), то делаем интерфейс IMallocInfo с методом GetReallocCaps. > Как раз самую элементарную информацию о методе (реализован/не > реализован) легко получить сравнив с NULL указатель на функцию.
Ага, это надо сравнивать его НА КАЖДЫЙ вызов. В результате вместо кода
получим макароны.
> Например ваша файловая система может поддерживать открытие файла по > некоторому номеру, другая только по имени, третья и по тому и по другому > признаку. В каждом случае вы зополняете только необходимые элементы > таблицы. vfs анализируя эту таблицу пользуется тем или иным способом.
Похоже на неоправданый хак. Для получения информации проще было бы
создать дополнительный интерфейс.
> C>Ни разу не было такого желания. > Элементарный hook какого-нибудь метода стороннего COM объекта
Для этого я всегда просто писал прокси-интерфейс. Гораздо удобнее
отлаживать.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[6]: Скорость работы с использованием классов и без
.. C>Просто IMalloc _обязан_ реализовать нужный функционал. Если изначально C>планируется возможность, что некоторые функции не будут реализованы — то C>пусть возвращают E_NOTIMPL. Пихать NULL в таблицу функций — это уже C>извращение.
... C>Ага, это надо сравнивать его НА КАЖДЫЙ вызов. В результате вместо кода C>получим макароны.
Не напоминает ли Вам это спор указатель vs ссылка?
Предлагаю закрыть вопрос.
>> Например ваша файловая система может поддерживать открытие файла по >> некоторому номеру, другая только по имени, третья и по тому и по другому >> признаку. В каждом случае вы зополняете только необходимые элементы >> таблицы. vfs анализируя эту таблицу пользуется тем или иным способом. C>Похоже на неоправданый хак. Для получения информации проще было бы C>создать дополнительный интерфейс.
Этот подход — результат эволюции UNIX/Linux OS.
Спорить о том, почему выжил именно этот подход, а не более правильный в теории предлагаю не начинать.
>> C>Ни разу не было такого желания. >> Элементарный hook какого-нибудь метода стороннего COM объекта C>Для этого я всегда просто писал прокси-интерфейс. Гораздо удобнее C>отлаживать.
Когда мне это понадобилось было лень писать прокси даже для 5 методов.
(В итоге решил проблему другим способом)
Re[7]: Скорость работы с использованием классов и без
MShura wrote: > C>Ага, это надо сравнивать его НА КАЖДЫЙ вызов. В результате вместо кода > C>получим макароны. > Не напоминает ли Вам это спор указатель vs ссылка?
А какой тут спор?
> Предлагаю закрыть вопрос.
Нет уж. Сам поднял его.
Если элементы в таблице функций по дизайну могут принимать NULLовое
значение, то их все перед вызовом надо проверять. А это медленно.
А если только некоторые функции могут быть NULL'ами, то почему бы их не
вынести в один интерфейс?
> C>Похоже на неоправданый хак. Для получения информации проще было бы > C>создать дополнительный интерфейс. > Этот подход — результат эволюции UNIX/Linux OS.
Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас
лень доставать мануалы.
> Спорить о том, почему выжил именно этот подход, а не более правильный в > теории предлагаю не начинать.
Ну так давно известно, что не все что написано — идеально.
>> > Элементарный hook какого-нибудь метода стороннего COM объекта > C>Для этого я всегда просто писал прокси-интерфейс. Гораздо удобнее > C>отлаживать. > Когда мне это понадобилось было лень писать прокси даже для 5 методов. > (В итоге решил проблему другим способом)
Ну так не надо писать руками
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[8]: Скорость работы с использованием классов и без
>> C>Ага, это надо сравнивать его НА КАЖДЫЙ вызов. В результате вместо кода >> C>получим макароны. >> Не напоминает ли Вам это спор указатель vs ссылка? C>А какой тут спор?
Если есть выбор использовать указатель или ссылку, то что лучше использовать.
Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок.
Я вижу такую аналогию, что таблица функций сгенеренная компилятором никогда не содержит пустые элементы, поэтому их можно вызывать без проверки. Ручная таблица и есть ручная.
C>Если элементы в таблице функций по дизайну могут принимать NULLовое C>значение, то их все перед вызовом надо проверять. А это медленно.
Если предполагается дальнейшее расширение интерфейса, то что быстрее:
— вызвать без проверки виртуальную функцию, проверить значение на "не реализовано", принять решение
— проверить на NULL указатель на функцию, принять решение
C>А если только некоторые функции могут быть NULL'ами, то почему бы их не C>вынести в один интерфейс?
Такой интерфейс легко расширяется.
Старый код продолжает работать ничего не зная о новых методах.
>> C>Похоже на неоправданый хак. Для получения информации проще было бы >> C>создать дополнительный интерфейс. >> Этот подход — результат эволюции UNIX/Linux OS. C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас C>лень доставать мануалы.
Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные заменить на заглушки возвращающие определенный код?
если понадобиться расширить vfs (а оно потихоньку расширяется), то придется переписывать старые драйвера?
(Т.е. добавлять пустые заглушки)
Re[9]: Скорость работы с использованием классов и без
MShura wrote: > C>А какой тут спор? > Если есть выбор использовать указатель или ссылку, то что лучше > использовать. > Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок.
Ну вообще-то указатель и ссылка — это разные вещи. В частности,
для ссылки гарантируется, что она не NULL и над ней нельзя делать
адресную арифметику.
> C>Если элементы в таблице функций по дизайну могут принимать NULLовое > C>значение, то их все перед вызовом надо проверять. А это медленно. > Если предполагается дальнейшее расширение интерфейса, то что быстрее: > — вызвать без проверки виртуальную функцию, проверить значение на "не > реализовано", принять решение > — проверить на NULL указатель на функцию, принять решение
Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы.
Ты еще не забудь, что тебе надо проверять ВСЕ функции. Либо надеяться,
что они будут реализованы.
> C>А если только некоторые функции могут быть NULL'ами, то почему бы их не > C>вынести в один интерфейс? > Такой интерфейс легко расширяется. > Старый код продолжает работать ничего не зная о новых методах.
Не понял.
Старые клиенты будут замечательно работать со старым IMalloc'ом (даже
если это IMapingMalloc), ничего не зная, про новый интерфейс.
> C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас > C>лень доставать мануалы. > Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные > заменить на заглушки возвращающие определенный код?
Нет, там у драйвера была функция, которая возвращала битовую маску с
возможностями драйвера.
> если понадобиться расширить vfs (а оно потихоньку расширяется), то > придется переписывать старые драйвера? > (Т.е. добавлять пустые заглушки)
Вообще-то, для новых функций обычно делают новые интерфейсы.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[10]: Скорость работы с использованием классов и без
>> C>А какой тут спор? >> Если есть выбор использовать указатель или ссылку, то что лучше >> использовать. >> Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок. C>Ну вообще-то указатель и ссылка — это разные вещи. В частности, C>для ссылки гарантируется, что она не NULL и над ней нельзя делать C>адресную арифметику.
Ссылка реализуется через указатель точно также, как виртуальные функции реализуются через таблицу функций.
указатель может быть NULL ссылка нет, указатель в таблице функций может быть NULL, указатель в таблице виртуальных функций нет.
По аналогии можно считать что в таблице виртуальных функций хранятся ссылки на функции.
>> C>Если элементы в таблице функций по дизайну могут принимать NULLовое >> C>значение, то их все перед вызовом надо проверять. А это медленно. >> Если предполагается дальнейшее расширение интерфейса, то что быстрее: >> — вызвать без проверки виртуальную функцию, проверить значение на "не >> реализовано", принять решение >> — проверить на NULL указатель на функцию, принять решение C>Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы.
Не согласен.
Как можно оптимизировать вызов виртуальной функции не зная точно типа объекта (конструкторы/деструкторы не рассматриваем)
Т.е. нужно сформировать аргументы, сделать call, проверить с определенным (скорее всего ненулевым) значением (проверка на нуль — самая простая).
Однозначно дольше.
C>Ты еще не забудь, что тебе надо проверять ВСЕ функции. Либо надеяться, C>что они будут реализованы.
Это верно.
>> C>А если только некоторые функции могут быть NULL'ами, то почему бы их не >> C>вынести в один интерфейс? >> Такой интерфейс легко расширяется. >> Старый код продолжает работать ничего не зная о новых методах. C>Не понял. C>
C>Старые клиенты будут замечательно работать со старым IMalloc'ом (даже C>если это IMapingMalloc), ничего не зная, про новый интерфейс.
>> C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас >> C>лень доставать мануалы. >> Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные >> заменить на заглушки возвращающие определенный код? C>Нет, там у драйвера была функция, которая возвращала битовую маску с C>возможностями драйвера.
>> если понадобиться расширить vfs (а оно потихоньку расширяется), то >> придется переписывать старые драйвера? >> (Т.е. добавлять пустые заглушки) C>Вообще-то, для новых функций обычно делают новые интерфейсы.
MShura wrote: > Теперь потребовалось расширить IFs > struct IFs > { > virtual int open(int) = 0; > virtual void close(int) = 0; > virtual int open(char*) = 0; > };
Вот для этого создаешь наследника:
struct IFsWithCharStar : public IFs
{
virtual int open(char*) = 0;
};
> Нет смысла менять код старых реализаций IFs. > Меняем только необходимые реализации.
Естественно.
> Код клиента: > // Для каждого зарегистрированного модуля (сервера) > IFs* fs = module_init(); > if ( NULL != fs->open2 ) > fs->open2( "/tmp" ); > else > fs->open(3);
IFsWithCharStar *efs=dynamic_cast<IFsWithCharStar *>(fs);
if (efs)
efs->open2(...);
else
fs->open(...);
Хотя это уже, скорее,пример плохого проектирования.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[11]: Скорость работы с использованием классов и без
MShura wrote: > C>Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы. > Не согласен. > Как можно оптимизировать вызов виртуальной функции не зная точно типа > объекта (конструкторы/деструкторы не рассматриваем) > Т.е. нужно сформировать аргументы, сделать call, проверить с > определенным (скорее всего ненулевым) значением (проверка на нуль — > самая простая). > Однозначно дольше.
В новых процессорах есть предсказатель косвенных переходов. Погугли по
словам "indirect branch prediction". Расходы на формирование списка
аргументов — возможны.
Хотя если код критически зависит по скорости от подобного приема — то я
бы использовал битовую маску.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[9]: Скорость работы с использованием классов и без
MShura wrote: >> > Этот подход — результат эволюции UNIX/Linux OS. > C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас > C>лень доставать мануалы. > Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные > заменить на заглушки возвращающие определенный код? > если понадобиться расширить vfs (а оно потихоньку расширяется), то > придется переписывать старые драйвера? > (Т.е. добавлять пустые заглушки)
Не стал бы я защищать решение в ядре Linux тем, что оно избавляет от
необходимости корректировать (простым образом) код старых драйверов в
ядре при эволюции ядра... Эта необходимость есть by design, во всяком
случае, так декларируется.
Posted via RSDN NNTP Server 2.0
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы. K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно? K>Интересно как дело обстоит когда мы используем только наследование? K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?
K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.
Чаще всего там, где падает скорость — это плата за безопасность. Например, вынос всех статических и стековых буферов в безопасные STL-коллекции. А те, в свою очередь, работают с кучей по-умолчанию, что не есть быстро. Если же скорость действительно критична, то применяют различные аллокаторы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Скорость работы с использованием классов и без
MS>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету. MS>Попробуйте в C++ виртуальности подменить виртуальную функцию.
Тоже элеметарно:
std::auto_ptr<IMalloc> a (new AllocImpl());
// выполняем действия с одной реализацией
a.reset(new AnotherAllocImpl); // Подменяем одну (или несколько) функций в таблице
// выполняем действия с другой реализацией
Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций.
Что вы хотели этим сказать?
В этом примере не IMalloc->Realloc равен NULL, а некоторая реализация этого интерфейса возвращает NULL.
Как может клиент, пользующийся IMalloc узнать релизован этот метод или нет?
MS>>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету. MS>>Попробуйте в C++ виртуальности подменить виртуальную функцию.
R>Тоже элеметарно:
R>
R>std::auto_ptr<IMalloc> a (new AllocImpl());
R>// выполняем действия с одной реализацией
R>a.reset(new AnotherAllocImpl); // Подменяем одну (или несколько) функций в таблице
R>// выполняем действия с другой реализацией
R>
Как это решает следующую задачу:
void bar( IMalloc* I );
void foo( IMalloc* I )
{
// Подмените здесь метод I->Realloc
bar( I );
// Восстановите метод I->Realloc
}
R>Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций.
Ровно столько-же сколько и их C++ аналоги.
Re[2]: Скорость работы с использованием классов и без
Здравствуйте, MShura, Вы писали:
R>>Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций. MS>Ровно столько-же сколько и их C++ аналоги.
Кажется ты говорил не о подмене функции для класса, а о подмене функции для объекта.
Считаем.
В классе С++ содержится один указатель на vtable класса (поясняю — 4 байта на 80x86).
Если ты собрался менять функции отдельно для каждого объекта, то значит у тебя каждый объект содержит свою таблицу функций. Т.е. если у объекта 10 таких функций, то таблица занимает 40 байт.
Или я что-то не так посчитал? Или ты предлагаешь какую-то другую реализацию?
MS>Что вы хотели этим сказать? MS>В этом примере не IMalloc->Realloc равен NULL, а некоторая реализация этого интерфейса возвращает NULL. MS>Как может клиент, пользующийся IMalloc узнать релизован этот метод или нет?
Практически все реальные задачи решатся методом который я привёл. Проверять наличие функции не цель, цель — сделать какую-то полезную работу.
Функцию Func, которую ты привёл в примере можно более тесно связать с классом IMalloc. Я уверен решение получится более правильное и без необходимости "обнулять" функции (под правильным я подразумеваю более информационно закрытое и менее провоцируещее дублирование).
В конце концов С++ программисты вполне замечательно 25 лет обходятся без таких фич, и что бы поднимался такой вопрос я вижу впервые.
См. пример, который я привёл ниже.
MS>>>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету. MS>>>Попробуйте в C++ виртуальности подменить виртуальную функцию.
R>>Тоже элеметарно:
R>>
R>>std::auto_ptr<IMalloc> a (new AllocImpl());
R>>// выполняем действия с одной реализацией
R>>a.reset(new AnotherAllocImpl); // Подменяем одну (или несколько) функций в таблице
R>>// выполняем действия с другой реализацией
R>>
MS>Как это решает следующую задачу:
MS>
MS>void bar( IMalloc* I );
MS>void foo( IMalloc* I )
MS>{
MS> // Подмените здесь метод I->Realloc
MS> bar( I );
MS> // Восстановите метод I->Realloc
MS>}
MS>
У C++ программистов есть более хорошие решения. Если надо именно изменять поведение во время выполнения, то вот пример:
IMalloc* I = new MallocImpl(new Strategy1Impl5(), new Strategy2Impl3());
// Подмените здесь метод I->Realloc
I->setStrategy2(new Strategy2Impl4());
bar( I );
// Восстановите метод I->Realloc
I->setStrategy2(new Strategy2Impl3());
Пожалуйста решение с подменой поведения, причём с большей поддержкой языка.
R>>>Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций. MS>>Ровно столько-же сколько и их C++ аналоги.
R>Кажется ты говорил не о подмене функции для класса, а о подмене функции для объекта. R>Считаем. R>В классе С++ содержится один указатель на vtable класса (поясняю — 4 байта на 80x86). R>Если ты собрался менять функции отдельно для каждого объекта, то значит у тебя каждый объект содержит свою таблицу функций. Т.е. если у объекта 10 таких функций, то таблица занимает 40 байт.
R>Или я что-то не так посчитал? Или ты предлагаешь какую-то другую реализацию?
Есть таблица функций, её можно расположить где хочешь (на стеке, в куче, глобально).
Кстати в C++ создается исключительно глобальная таблица и только в const секции.
Объект содержит указатель на эту таблицу.
Создаем копию таблицы. Меняем в ней один или несколько элементов. В подопытном объекте меняем указатель на новую таблицу.
Всё.
Ровно столько же придется делать на C++, но поскольку только компилятор имеет возможность управлять таблицей функций, то придется делать еще один класс (proxy для подопытного).
Итого тоже две таблицы, но неуправляемые программистом.
Re[7]: Скорость работы с использованием классов и без
R>В конце концов С++ программисты вполне замечательно 25 лет обходятся без таких фич, и что бы поднимался такой вопрос я вижу впервые.
Но это не значит, что таких задач нет.
MS>>Как это решает следующую задачу:
MS>>
MS>>void bar( IMalloc* I );
MS>>void foo( IMalloc* I )
MS>>{
MS>> // Подмените здесь метод I->Realloc
MS>> bar( I );
MS>> // Восстановите метод I->Realloc
MS>>}
MS>>
R>У C++ программистов есть более хорошие решения. Если надо именно изменять поведение во время выполнения, то вот пример:
R>
R>IMalloc* I = new MallocImpl(new Strategy1Impl5(), new Strategy2Impl3());
R>// Подмените здесь метод I->Realloc
I->>setStrategy2(new Strategy2Impl4());
R>bar( I );
R>// Восстановите метод I->Realloc
I->>setStrategy2(new Strategy2Impl3());
R>
R>Пожалуйста решение с подменой поведения, причём с большей поддержкой языка.
Как это решает вышеприведенную задачу я так и не понял.
В моем вопросе в функции foo есть внешний IMalloc* I.
Вы должны вызвать bar() так, чтобы только одна из функций это объекта была переопределена, а остальные были прежними.
Одним словом я не вижу, что вы делаете с внешним IMalloc* I.
Я вижу, что вы заводите новую реализацию IMalloc( не имеющую отношения к входному I ) и передаете её в bar().
Re[2]: Скорость работы с использованием классов и без
Cyberax wrote:
>> Теперь потребовалось расширить IFs
[сcode] >> struct IFs >> { >> virtual int open(int) = 0; >> virtual void close(int) = 0; >> virtual int open(char*) = 0; >> };
[/сcode] > Вот для этого создаешь наследника:
Не... нехорошо... а если так? Добавляем новый интерфейс и модифицируем старый (оставляя весь старый код компилябельным):
trophim wrote: > C>Во-вторых, в новых процессорах есть специальные аппаратные оптимизации > C>косвенного вызова. > А я в танке видимо... Про что речь? Можно чуть поподробнее? Какие > оптимизации?
Запоминается куда в прошлый раз делалось косвенное обращение. Почитайте
про предиктор в новых Intel Core.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы. K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
Не секрет, например, что на C зачастую (я не говорю — обязательно!) пишут простую обработку структуры данных одной функцией вместо нагромождения адаптеров, фасадов и прочего.
Также не секрет, что по умолчанию STL (по крайней мере, в VC++) использует общий malloc/free для управлеия памятью, то есть вот такая конструкция:
void func()
{
std::string s = "this is my string";
}
это два обращения к хипу на каждый вызов (конструктур/деструктор).
На этом фоне расходы на VMT почти не заметны.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[2]: Скорость работы с использованием классов и без
Геннадий Васильев wrote: > std::string s = "this is a string"; > это два обращения к хипу на каждый вызов (конструктур/деструктор).
А вот для такой строки — ноль обращений (в реализации Dinkumware):
std::string s = "just a string";
А еще есть const_string, где можно использовать так:
const_string<char> str(boost::cref("just a string"));
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[2]: Скорость работы с использованием классов и без
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, Kokoban, Вы писали:
K>>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы. K>>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
ГВ>Не секрет, например, что на C зачастую (я не говорю — обязательно!) пишут простую обработку структуры данных одной функцией вместо нагромождения адаптеров, фасадов и прочего.
Не секрет, что программисты на С зачастую (я имею в виду практически всегда) для хранения строк используют char*, при этом для вычисления длины строки при каждом удобном и неудобном случае используют strlen(). В результате чего получается следующее:
char* request = ...;
int generateSome()
{
char* xxx = request;
int len = strlen(request); //1
}
send(sock, request, strlen(request), 0); //2int generateSome2()
{
char* xxx2 = request;
int len2 = strlen(request); //3
}
if (strncmp(request, request2, min(strlen(request), strlen(request2))); //3 //4
Что такое strlen() Вы понимаете — перелопачивание всей памяти строки с загрузкой её в кэш из памяти и с выгрузкой из кэша других нужных данных.
Таких ненужных strlen в программе С программиста я обычно насчитываю десятки. А ничего подобного я ни разу не видел:
Здравствуйте, Kokoban, Вы писали:
K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
А как, интересно, С программист эмулирует то поведение, которое С++ получил с применением таблицы виртуальных функций ???
Он сделает это как-то эффективнее с т.з. вычислительной или ёмкостной сложности ??? У него это будет удобнее ???
Аналогично относительно других фич С++, относительно которых С программисты считают, что они замедляют программу.
Здравствуйте, FR, Вы писали:
ГВ>>это два обращения к хипу на каждый вызов (конструктур/деструктор). FR>Именно такая и именно в VC >7.0 не вызовет ни одного обращения к хипу, строка маленька и помещается в буфер на стеке
Я о другом, о том, что new/delete могут оказаться в неожиданных на первый взгляд местах и поспособствовать кое-каким заблуждениям.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: Скорость работы с использованием классов и без
Здравствуйте, Cyberax, Вы писали:
C>А еще есть const_string, где можно использовать так: C>
C>const_string<char> str(boost::cref("just a string"));
C>
Сдаётся мне, что те, кто "лазят в буст" не создают мифов о проигрышах C++ перед C.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: Скорость работы с использованием классов и без
R>Не секрет, что программисты на С зачастую (я имею в виду практически всегда) для хранения строк используют char*, при этом для вычисления длины строки при каждом удобном и неудобном случае используют strlen(). В результате чего получается следующее:
.... R>Таких ненужных strlen в программе С программиста я обычно насчитываю десятки. А ничего подобного я ни разу не видел:
R>
Как любят говорить на этом форуме: "отучаемся говорить за всех".
Посмотрите на структуру UNICODE_STRING в Windows или qstr в Linux.
Я пользуюсь ими а Вы?
Re[4]: Скорость работы с использованием классов и без
MShura wrote:
> R>typedef struct > R>{ > R> char* str; > R> int len; > R>} string; > R> > > > > Как любят говорить на этом форуме: "отучаемся говорить за всех". > Посмотрите на структуру UNICODE_STRING в Windows или qstr в Linux. > Я пользуюсь ими а Вы?
Во-во. А переносимость?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Скорость работы с использованием классов и без
Здравствуйте, Cyberax, Вы писали:
C>В-третьих, можно замечательно использовать ООП без виртуальных функций. C>В качестве примера можно взять STL.
STL это вроде бы не ООП. Ну вот к примеру:
Generic Programming and the STL: Using and Extending the C++ Standard Template Library (Hardcover)
by Matthew H. Austern
. . .
This is not a book about object-oriented programming.
You may think that's odd. You probably found this book in the C++ section of the bookstore, after all, and you've probably heard people use object oriented and C++ synonymously, but that isn't the only way to use the C++ language. C++ supports several fundamentally different paradigms, the newest and least familiar of which is generic programming.
Здравствуйте, kan_izh, Вы писали:
_>MShura wrote:
>> R>typedef struct >> R>{ >> R> char* str; >> R> int len; >> R>} string; >> R> >> >> >> >> Как любят говорить на этом форуме: "отучаемся говорить за всех". >> Посмотрите на структуру UNICODE_STRING в Windows или qstr в Linux. >> Я пользуюсь ими а Вы? _>Во-во. А переносимость?
Согласен, возможно, я зря сказал за всех.
Активное пользование такой структурой в приложении похвально. Но.
1. Полностью это не изменит ситуацию, т.к. посмотрите на WinAPI и на другие c-style библиотеки. Какие-нибудь из них принимают такие структуры? Правильно, Нет! Значит опять возвращаемся к strlen().
Посмотрите, например, на функцию strdup(). Что она делает? Правильно, вначале вызывает strlen(), что бы один раз "пробежаться" по строке, выделяет память, а потом при копировании ещё раз "пробегает" по строке.
Я, конечно, не говорю, что оптимизации нельзя реализовать вручную. Да, можно сделать структуру с длиной, можно самому реализовать все функции для работы со строками над этой структурой.
2. В С++ такие оптимизации обеспечиваются автоматически. Быстрый код получается при минимуме усилий.
А С приминуме усилий даёт не такой эффективный код. А что бы получить такую же эффективность как в С++ надо попариться — реализовывать вручную функции работы со строками, эмулировать таблицы виртуальных функций и т.д.
R>Активное пользование такой структурой в приложении похвально. Но. R>1. Полностью это не изменит ситуацию, т.к. посмотрите на WinAPI и на другие c-style библиотеки. Какие-нибудь из них принимают такие структуры? Правильно, Нет! Значит опять возвращаемся к strlen().
Смотрю на другую C-style библиотеку DDK.
Все функции этой библиотеки принимают структуры (UNICODE_STRING,ANSI_STRING).
Так что лишних wcslen/strlen нет и в помине.
R>Посмотрите, например, на функцию strdup(). Что она делает? Правильно, вначале вызывает strlen(), что бы один раз "пробежаться" по строке, выделяет память, а потом при копировании ещё раз "пробегает" по строке.
Нет необходимости в этой функции если есть длина строки.
R>Я, конечно, не говорю, что оптимизации нельзя реализовать вручную. Да, можно сделать структуру с длиной, можно самому реализовать все функции для работы со строками над этой структурой. R>2. В С++ такие оптимизации обеспечиваются автоматически. Быстрый код получается при минимуме усилий. R>А С приминуме усилий даёт не такой эффективный код. А что бы получить такую же эффективность как в С++ надо попариться — реализовывать вручную функции работы со строками, эмулировать таблицы виртуальных функций и т.д.
Тем не менее все ядра (Windows/Linux) написаны именно на C. Наверное чтобы осталось место для дальнейшей оптимизации
Вы уже приводили пример плохого использования C. Я могу элементарно привести пример плохого использования языка C++
MShura wrote: > Написать на C то, что делает здесь компилятор C++ не сможет ни один > человек в здравом уме.
А вот с const_string'ом все будет замечательно, потому как expression
templates.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
Здравствуйте, Kokoban, Вы писали:
K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.
У меня, как заядлого "плюсовика" свои счеты с C++, но сия претензия как-то не вылазила. Ибо, есть куда более серьезные.
Самая главная — это "неопределенность" с библиотечным кодом.
Что в C хорошо, так это то, что неважно каким компилером скомпилирована библиотека. Подключай ее в линковку и будет тебе щасце, если форматы обьектного кода совпадают.
В C++ все куда более запущено. И все из-за того что на большинстве платформ у каждого компилера свои соглашения по форматам Name mangling, RTTI, исключений, работы с памятью. В итоге, чтобы щчасце получилось, приходится провайдить скомпилированные библиотеки не только для каждого брэнда компилеров (например, Borland, Microsoft, GNU), но и для каждой ВЕРСИИ компилера (особо актуально для Microsoft Visual C++).
Есть только одна платформа где с этим более или менее порядок — это Линух. И все потому что "главный" компилятор там GCC с открытыми исходниками и посему вменяемые компании (например, Intel) компиляторы для линуха выпускают GCC-совместимыми. Ничего не буду говорить за Borland Kylix тк не знаю.
Мораль, однако, такова. Из "безгеморных" вариантов распространения библиотек на C++ есть только один — распространение в исходниках. Во что превращаются другие варианты распростанения — добро пожалть в BOOST — посмотри сколько есть вариантов .dll-ей для BOOST::Regex Это тем более справедливо для распространения библиотек шаблонов (templates) — для них распространение в исходниках — это единственный вариант. За примерами — туда же — www.boost.org .
K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
Косвенный вызов против прямого. Проверить как это бьет по производительности — тривиально. Тем более, матерому сишнику. Надо только учесть, что виртуальных методов не так уж и много. Точнее, должно быть немного. Но бывает наоборот и тогда они превращаются в геморрой. Пример — реализация (требуемая стандартом) библиотеки потоков ввода-вывода (iostream). Часто народ ругается что большая она и тормознутая, но почему-то никто не переписывает.
K>Интересно как дело обстоит когда мы используем только наследование?
Никак. Наследование на производительность серьезно не влияет. Адреса вызовов к не-виртуальным методам разрешаются во время компиляции и, следовательно эквивалентны вызовам функций. С виртуальными — то же самое плюс косвенный вызов.
Не скажу за наследование виртуальное. Что влияет отрицательно — это скорее "да", чем "нет". Но конкретных цифр привести не могу тк область применения виртуального наследования относительно узка и из-за него никогда не возникало проблем производительности.
Что тормозит конкретно — это dynamic_cast, но в большинстве случаев без него можно обойтись.
K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?
Добавляется только "спрятанный" параметр в вызовах функций. А именно — указатель на класс — this.
__________
16.There is no cause so right that one cannot find a fool following it.
Re[6]: Скорость работы с использованием классов и без
Здравствуйте, remark, Вы писали:
R>Согласен, возможно, я зря сказал за всех. R>Активное пользование такой структурой в приложении похвально. Но. R>1. Полностью это не изменит ситуацию, т.к. посмотрите на WinAPI и на другие c-style библиотеки. Какие-нибудь из них принимают такие структуры? Правильно, Нет! Значит опять возвращаемся к strlen().
Неправильно. Большинство функций WinAPI принимают и возвращают длину вместе со строкой. Так что вместо strlen нужно просто аккуратно использовать эту информацию. R>Посмотрите, например, на функцию strdup(). Что она делает? Правильно, вначале вызывает strlen(), что бы один раз "пробежаться" по строке, выделяет память, а потом при копировании ещё раз "пробегает" по строке.
Совершенно верно. От strdup лучше отказаться, как и еще от нескольких традиционных конструкций, чреватых buffer overrun или performance degradation. R>Я, конечно, не говорю, что оптимизации нельзя реализовать вручную. Да, можно сделать структуру с длиной, можно самому реализовать все функции для работы со строками над этой структурой. R>2. В С++ такие оптимизации обеспечиваются автоматически. Быстрый код получается при минимуме усилий. R>А С приминуме усилий даёт не такой эффективный код. А что бы получить такую же эффективность как в С++ надо попариться — реализовывать вручную функции работы со строками, эмулировать таблицы виртуальных функций и т.д.
С этим согласен.
R>
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Скорость работы с использованием классов и без
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, remark, Вы писали:
R>>Согласен, возможно, я зря сказал за всех. R>>Активное пользование такой структурой в приложении похвально. Но. R>>1. Полностью это не изменит ситуацию, т.к. посмотрите на WinAPI и на другие c-style библиотеки. Какие-нибудь из них принимают такие структуры? Правильно, Нет! Значит опять возвращаемся к strlen(). S>Неправильно. Большинство функций WinAPI принимают и возвращают длину вместе со строкой. Так что вместо strlen нужно просто аккуратно использовать эту информацию.
Могу с тем же успехом сказать обратное
Согласен, что функции, которые работают с большими объёмами данных скорее всего принимают размер (WSASend, MultiByteToWideChar).
Но большинство других функций не принимают размер.
Тут стоит подумать над самим подходом — типа пока не припрёт, размер передавать не будем, пусть память постоянно зря перелопачивается. Тем более, что у меня функция уже принимает 8 параметров, если я ещё и размеры строк буду принимать, то получится 13, лучше уж я сам длину посчитаю. В С++ другой подход — вместе со строкой всегда передаём размер.
Здравствуйте, 0xDEADBEEF, Вы писали:
K>>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно? DEA>Косвенный вызов против прямого. Проверить как это бьет по производительности — тривиально. Тем более, матерому сишнику. Надо только учесть, что виртуальных методов не так уж и много. Точнее, должно быть немного. Но бывает наоборот и тогда они превращаются в геморрой. Пример — реализация (требуемая стандартом) библиотеки потоков ввода-вывода (iostream). Часто народ ругается что большая она и тормознутая, но почему-то никто не переписывает.
K>>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов? DEA>Добавляется только "спрятанный" параметр в вызовах функций. А именно — указатель на класс — this.
Что мы сравниваем???
Такое ощущение, что мы (и практически все в подобных беседах, особенно Сишники) сравнивают по производительности программку на С из одной функции и 10 строк кода и проект на С++ из 100К строк кода, содержащий огромные иерархии классов, кучи виртуальных функций и т.д. Но это по меньшей мере не объективно и не профессионально, да и просто нечестно.
На ставить одинаковые задачи для обоих языков!
"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров?
А как бы такая же задача решалась на С?
В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this.
А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее?
Про виртуальные функции. С++ программист просто так их не вводит, С-программисту придётся что-то вручную наворачивать, что бы съэмулировать аналогичное поведение.
Самые очевидные:
1. Съэмулировать таблицу виртуальных функций. Не получаем никаких выгод, только необходимость всё делать ручками (применяется редко).
2. Повсеместно использовать Switch-On-Type (применяется часто). Проигрываем по скорости, проигрываем по памяти + приходится везде дублировать SOT + склонно к ошибкам...
Предлагаю вообще переформулировать вопрос следующим образом:
Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?
R>"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров? R>А как бы такая же задача решалась на С?
Точно также и решается.
Явный указатель на структуру данных.
R>В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this. R>А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее?
Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование.
Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL.
ЭТО НЕВОЗМОЖНО.
R>Предлагаю вообще переформулировать вопрос следующим образом: R>Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?
При правильном использовании C++ его производительность будет приближаться к C.
Подумайте например какой ценой можно завести C++ объект в любом месте функции.
R>>"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров? R>>А как бы такая же задача решалась на С? MS>Точно также и решается. MS>Явный указатель на структуру данных.
Я это и написал. Но в чём тогда смысл высказывания "С++ тормозит"?
R>>В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this. R>>А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее? MS>Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование. MS>Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL. MS>ЭТО НЕВОЗМОЖНО.
В С++ можно [практически] всё, что можно в С. За очень редким исключением, и возможности сделать такую библиотеку это не касается.
R>>Предлагаю вообще переформулировать вопрос следующим образом: R>>Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?
MS>При правильном использовании C++ его производительность будет приближаться к C.
Да, но только [почти] максимальной производительности на С++ можно добится очень лёгко и без геммороя, а в С — сложно и с геммороем.
MS>Подумайте например какой ценой можно завести C++ объект в любом месте функции.
Здравствуйте, remark, Вы писали:
R>"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров?
По сравнению ни c чем. Его просто не видно.
Для сишника, привыкшего видеть все, это может оказаться неприятным сюрпризом.
Поэтому я и озвучил эту азбучную истину.
R>А как бы такая же задача решалась на С?
Это — неважно. В C и C++ те же самые задачи решаются различными способами.
Просто потому, что один язык — ОО, а второй — процедурный.
Если хочешь иллюстрацию — посмотри на две реализации XML-парсеров. Обе — весьма "взрослые". Обе — решают одну и ту же проблему. Но, одна на C (libxml) а вторая — на C++ (xerces/xalan).
R>Предлагаю вообще переформулировать вопрос следующим образом: R>Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?
Какой производительности? Производительности кода или программиста?
Если программиста, то С++ кроет C как бык овцу. Т.к. обьектная модель берет на себя массу рутинных задач типа управления владением. Про контейнеры STL вообще говорить не надо — ничего сравнимого с их мощью в C просто нету. Есть некоторые потуги (например, libiberty), но это именно потуги.
Но... именно мощь C++ и его позволяет написать программисту на порядки больше чепухи, чем его собрату — сишнику. Просто, в силу того, что многие "затратные" вещи C++-ник использует неявно, через полиморфные вызовы или просто в силу недостаточного знакомства с обьектной моделью приложения. Или просто в силу того что обьектная модель кривая (поклон архитекторам).
В C, с другой стороны, все делается явно (терминальные случаи злоупотребления макросами в расчет не берем). Программист явно видит что он вызывает. Косвенность в большинстве случаев не используется. Получается, что он куда ближе к "железу" чем C++-ник. Для него куда более очевидна зависимость "больше кода — медленнее программа" и куда более очевидно каким будет его код в бинарном виде.
Чтобы не быть голословным, посчитай как часто употребляют "static" для не-глобальных функций сишники и C++-ники. Вроде бы мелочь, а вот на юнихах сишные .so грузятся намнооого быстрее, чем C++-ные.
Далее, полистай форум rsdn.cpp.applied и посмотри насколько часто возникают проблемы у форумчан с C+-ными .DLL-ями, и насколько часто — с сишными.
ЗЫ. Впрочем, любое мнение можно довести до абсурда. Мое — в том числе . Достаточно только вcпомнить что наиболее компактные и производительные программы пишутся на ассемблере Но мораль остается все той же. Чем сильнее язык абстрагируется от "железа", тем больше эта абстракция бьет по коду — его размеру, производительности и т.д. Вопрос только готовы мы или нет платить эту цену за абстракцию...
__________
16.There is no cause so right that one cannot find a fool following it.
MShura wrote: > Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли > пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с > разными STL. > ЭТО НЕВОЗМОЖНО.
Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA.
0xDEADBEEF wrote: > Если хочешь иллюстрацию — посмотри на две реализации XML-парсеров. Обе — > весьма "взрослые". Обе — решают одну и ту же проблему. Но, одна на C > (libxml) а вторая — на C++ (xerces/xalan).
libxml — это как раз хороший пример объектно-ориентированного
программирования.
R>>>"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров? R>>>А как бы такая же задача решалась на С? MS>>Точно также и решается. MS>>Явный указатель на структуру данных.
R>Я это и написал. Но в чём тогда смысл высказывания "С++ тормозит"?
При передаче аргументов никаких.
R>>>В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this. R>>>А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее? MS>>Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование. MS>>Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL. MS>>ЭТО НЕВОЗМОЖНО.
R> В С++ можно [практически] всё, что можно в С. За очень редким исключением, и возможности сделать такую библиотеку это не касается.
Только интерфес у этого API будет C.
Т.е. нельзя использовать std::string в качестве аргументов/возвращаемого значения, если вы хотите, чтобы кто-то кроме вас использовал вашу библиотеку/API.
R>>>Предлагаю вообще переформулировать вопрос следующим образом: R>>>Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?
MS>>При правильном использовании C++ его производительность будет приближаться к C.
R>Да, но только [почти] максимальной производительности на С++ можно добится очень лёгко и без геммороя, а в С — сложно и с геммороем.
речь шла о производительности программы.
Ну а что касается дополнительного кода, то лучше написать больше, но при этом все контролировать.
К тому же по сравнению с общим временем разработки программы доля написания дополнительного кода очень несущественна.
А сокрытие деталей плохо сказывается на читаемости программы.
MS>>Подумайте например какой ценой можно завести C++ объект в любом месте функции.
R> Разместить его на стеке?
Обычно это дополнительная (неуправляеммая вами) переменная, которая используется для выяснения вызывался конструктор или нет.
Здравствуйте, Cyberax, Вы писали:
C>0xDEADBEEF wrote: >> Если хочешь иллюстрацию — посмотри на две реализации XML-парсеров. Обе — >> весьма "взрослые". Обе — решают одну и ту же проблему. Но, одна на C >> (libxml) а вторая — на C++ (xerces/xalan). C>libxml — это как раз хороший пример объектно-ориентированного программирования.
...тогда примером какого программирования служит xerces? Тоже обьектно-ориентированного?
Если да, то не находишь ли ты, подходы к обьектной ориентации у C и C++ несколько различны?
__________
16.There is no cause so right that one cannot find a fool following it.
0xDEADBEEF wrote: > C>libxml — это как раз хороший пример объектно-ориентированного > программирования. > ...тогда примером какого программирования служит xerces? Тоже > обьектно-ориентированного?
Да. Стандарт DOM XML — это, фактически, хрестоматийный пример ООП.
> Если да, то не находишь ли ты, подходы к обьектной ориентации у C и C++ > несколько различны?
То есть "подходы"? Они одинаковы, просто в С++ паттерны ООП
(наследование и виртуальность) вмонтированы в язык, а в С их нужно
делать самому.
Здравствуйте, Cyberax, Вы писали:
C>MShura wrote: >> Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли >> пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с >> разными STL. >> ЭТО НЕВОЗМОЖНО. C>Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA.
MShura wrote: >> > Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли >> > пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с >> > разными STL. >> > ЭТО НЕВОЗМОЖНО. > C>Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA. > Покажите мне std::string в COM.
А зачем std::string? Есть comet::bstr_t, которая совместима с
std::string по API.
Здравствуйте, Cyberax, Вы писали:
C>0xDEADBEEF wrote: >> C>libxml — это как раз хороший пример объектно-ориентированного >> программирования. >> ...тогда примером какого программирования служит xerces? Тоже >> обьектно-ориентированного? C>Да. Стандарт DOM XML — это, фактически, хрестоматийный пример ООП.
...потому что reference реализация на Jave-была.
>> Если да, то не находишь ли ты, подходы к обьектной ориентации у C и C++ несколько различны? C>То есть "подходы"? Они одинаковы, просто в С++ паттерны ООП (наследование и виртуальность) вмонтированы в язык, а в С их нужно делать самому.
...что характерно, полиморфизм (т.е "виртуальность") в libxml используется куда более ограниченно, чем в Xerces. И, главное, такое положение дел совсем не во вред...
Теперь, почему я привел этот пример: remark писал: "Про виртуальные функции. С++ программист просто так их не вводит, С-программисту придётся что-то вручную наворачивать, что бы съэмулировать аналогичное поведение.". Я же хотел показать, что там, где C++-ник схватится за полиморфизм или еще какую фичу языка (например RAII), сишник применит другой подход.
То есть, несмотря на то, что задачи эквивалентны, способы их решения на C и C++ различаются достаточно сильно и сводить их к "эмуляции аналогичного поведения" — глупость.
__________
16.There is no cause so right that one cannot find a fool following it.
Здравствуйте, Cyberax, Вы писали:
C>MShura wrote: >>> > Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли >>> > пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с >>> > разными STL. >>> > ЭТО НЕВОЗМОЖНО. >> C>Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA. >> Покажите мне std::string в COM. C>А зачем std::string? Есть comet::bstr_t, которая совместима с C>std::string по API.
C>А еще есть http://www.zeroc.com/icee/cpp.html — там как раз std::string C>в API.
И этим API можно пользоваться из VB, Дельфи, C, а также из разных версий компилятора C++ с разными STL?
MShura wrote:
> MS>>Подумайте например какой ценой можно завести C++ объект в любом > месте функции. > > R> Разместить его на стеке? > Обычно это дополнительная (неуправляеммая вами) переменная, которая > используется для выяснения вызывался конструктор или нет.
Ты о чём? Зачем это выяснять? Вызов конструктора (если он есть!) происходит в том месте, где поставлена переменная. Т.е.
этот код:
struct A
{
A():i(0){}
int i;
};
...
A a;
...
Полностью аналогичен:
struct A
{
int i;
};
void constructA(A *a)
{
a->i = 0;
}
...
A a;
constructA(&a);
...
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
>> R> Разместить его на стеке? >> Обычно это дополнительная (неуправляеммая вами) переменная, которая >> используется для выяснения вызывался конструктор или нет. _>Ты о чём? Зачем это выяснять? Вызов конструктора (если он есть!) происходит в том месте, где поставлена переменная. Т.е.
А если возврат из функции произошел раньше вызова конструктора?
Память для локальных переменных обычно выделяется при входе в функцию, т.е. даже для того, объекта который будет проинициалирован позже память уже выделена.
При раскрутке стека необходимо знать был ли проинициализорован объект с нетривиальным деструктором.
MShura wrote: > А если возврат из функции произошел раньше вызова конструктора?
Ну ты сам сказал — вызова конструктора не будет.
> При раскрутке стека необходимо знать был ли проинициализорован объект с > нетривиальным деструктором.
Не обязательно. В случае табличных исключений — мы знаем какие
конструкторы уже отработали в данный момент.
MShura wrote: > C>А зачем std::string? Есть comet::bstr_t, которая совместима с > C>std::string по API. > C>А еще есть http://www.zeroc.com/icee/cpp.html — там как раз std::string > C>в API. > И этим API можно пользоваться из VB, Дельфи, C, а также из разных версий > компилятора C++ с разными STL?
В разных версиях С++ — без проблем. Для VB/Delphi у них интерфейса нет.
Если нужен совсем глобальный интерфейс — то еще раз смотри COM.
C>В разных версиях С++ — без проблем. Для VB/Delphi у них интерфейса нет.
Хорошо я еще раз процитирую своё предложение, с которым возникло несогласие
Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование.
Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL.
ЭТО НЕВОЗМОЖНО.
C>Если нужен совсем глобальный интерфейс — то еще раз смотри COM.
Опять же если этот интерфейс можно использовать в VB/Deplhi, то это не может быть C++ инерфейсом.
>> А если возврат из функции произошел раньше вызова конструктора? C>Ну ты сам сказал — вызова конструктора не будет.
С элементарным случаем согласились
>> При раскрутке стека необходимо знать был ли проинициализорован объект с >> нетривиальным деструктором. C>Не обязательно. В случае табличных исключений — мы знаем какие C>конструкторы уже отработали в данный момент.
Пусть рассматириваемая функция вызвала другую, в которой произошло исключение. В нашей функции мы ислючение не ловим, а кто-то сверху его поймал. Вызывают раскрутку стека для каждой вызванной функции.
Во время раскрутки стека вызывается специальная функция, которая была создана компилятором для этих целей.
Вот перед нами фрейм с локальнами объектами. Кто-то проинициализорован, кто-то нет. Для кого вызывать деструкторы?
MShura wrote: > Основное преимущество библиотек написанных на C (вернее с C интерфейсом) > — их использование. > Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли > пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с > разными STL. > ЭТО НЕВОЗМОЖНО.
Это утверждение неверно.
Во-первых, никто не мешает на С++ писать библиотеки с С-шным интерфейсом
(смотри, например, ODE — http://www.ode.org).
Во-вторых, можно использовать подход как в COM. То есть с интерфейсами+
QueryInterface и набором поддерживающих объектов (строки, массивы).
> C>Если нужен совсем глобальный интерфейс — то еще раз смотри COM. > Опять же если этот интерфейс можно использовать в VB/Deplhi, то это не > может быть C++ инерфейсом.
А если библитека на С используется из Pascal, то это уже не C-интерфейс?
MShura wrote: > C>Не обязательно. В случае табличных исключений — мы знаем какие > C>конструкторы уже отработали в данный момент. > Пусть рассматириваемая функция вызвала другую, в которой произошло > исключение. В нашей функции мы ислючение не ловим, а кто-то сверху его > поймал. Вызывают раскрутку стека для каждой вызванной функции. > Во время раскрутки стека вызывается специальная функция, которая была > создана компилятором для этих целей. > Вот перед нами фрейм с локальнами объектами. Кто-то проинициализорован, > кто-то нет. Для кого вызывать деструкторы?
Компилятор при генерации строить специальные таблицы, по котором для
каждого положения указателя инструкций можно определить какие
деструкторы надо вызвать для размотки функции.
То есть для каждой функции имеем таблицу с записями вида "EIP —
destructor", упорядоченную по росту EIP. Соответственно, при размотке
стека по достижении начала функции мы смотрим в стек адрес возврата в
вызывающую функцию. По этому адресу берем таблицу размотки для функции и
разматываем те конструкторы, которые уже выполнились (для которых EIP
меньше адреса возврата).
В итоге имеем нулевой оверхед по скорости в случае нормальной работы, но
некоторый оверхед по объему исполняемого файла (так как таблицы нужно
хранить).
Кстати, в чистом С такое повторить не получится (точнее с ооооочень
большими трудозатратами).
C>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>большими трудозатратами).
В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
C>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>большими трудозатратами).
MS>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
Инициализируются в смысле под них выделяется хранилище (память)?
C>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>большими трудозатратами).
MS>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
>> Основное преимущество библиотек написанных на C (вернее с C интерфейсом) >> — их использование. >> Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли >> пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с >> разными STL. >> ЭТО НЕВОЗМОЖНО. C>Это утверждение неверно. C>Во-первых, никто не мешает на С++ писать библиотеки с С-шным интерфейсом C>(смотри, например, ODE — http://www.ode.org).
А никто не спорит что внутре ((c) Выбегалло ) API может быть написано на любом языке.
Тот-же WinApi частично написан на C++ (некоторые из shell функций).
C>Во-вторых, можно использовать подход как в COM. То есть с интерфейсами+ C>QueryInterface и набором поддерживающих объектов (строки, массивы).
Тем не менее сам интерфейс остается C.
Хотя можно сколько угодно накручивать C++ обертки, но только поверх C интерфейса.
>> C>Если нужен совсем глобальный интерфейс — то еще раз смотри COM. >> Опять же если этот интерфейс можно использовать в VB/Deplhi, то это не >> может быть C++ инерфейсом. C>А если библитека на С используется из Pascal, то это уже не C-интерфейс?
Не понял.
Резюмируя хочу сказать, что преимущество C интерфейса именно в том, что им можно пользоваться из любого другого языка.
C>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>>большими трудозатратами).
MS>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
К>OutOfMemory очено ожиданный возврат?
Как может возникнуть OutOfMemory при инициализации локальных переменных константными значениями?
C>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>>большими трудозатратами).
MS>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
R>Инициализируются в смысле под них выделяется хранилище (память)?
Под локальные переменные память выделяет пролог функции.
Сами локальные переменные инициализируется уникальным константным значением (например NULL)
C>>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>>>большими трудозатратами).
MS>>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
К>>OutOfMemory очено ожиданный возврат? MS>Как может возникнуть OutOfMemory при инициализации локальных переменных константными значениями?
локальная переменная, скажем массив целых на 100000 байт, функция рекурсивная, как кончится память догадаешься?
Или у тебя своя терминология и локальная переменная только на стеке? но, надеюсь, ты в курсе, что стек вещь не бесконечная?
Здравствуйте, MShura, Вы писали:
C>>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень C>>>>большими трудозатратами).
MS>>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
R>>Инициализируются в смысле под них выделяется хранилище (память)? MS>Под локальные переменные память выделяет пролог функции. MS>Сами локальные переменные инициализируется уникальным константным значением (например NULL)
Неужели тоже самое только (опять) вручную???
Или С-программисты делают как-то по-другому? В С-стиле программирования не силён, поэтому поправьте, если что.
MShura wrote: > C>Кстати, в чистом С такое повторить не получится (точнее с ооооочень > C>большими трудозатратами). > В C такой задачи не стоит, поскольку локальные "объекты" > инициализируются в начале функции, до того, как могут возникнуть > какие-либо исключения или другие неожиданные возвраты.
Да? И наверное именно поэтому один из самых распространенных паттернов в
С — это обработка ошибок через goto:
void func()
{
char *ptr1=NULL,*ptr2=NULL;
ptr1=malloc(...);
if (!ptr1) goto err_1;
ptr2=malloc(...);
if (!ptr2) goto err_2;
err2: free(ptr2);
err1: free(ptr1);
};
>> C>Кстати, в чистом С такое повторить не получится (точнее с ооооочень >> C>большими трудозатратами). >> В C такой задачи не стоит, поскольку локальные "объекты" >> инициализируются в начале функции, до того, как могут возникнуть >> какие-либо исключения или другие неожиданные возвраты. C>Да? И наверное именно поэтому один из самых распространенных паттернов в C>С — это обработка ошибок через goto: C>
R>Неужели тоже самое только (опять) вручную??? R>Или С-программисты делают как-то по-другому? В С-стиле программирования не силён, поэтому поправьте, если что.
Одна точка входа и одна точка выхода -> наиболее распространенный стиль программирования.
Примеры можно посмотреть в Linux или в Windows (DDK).
К>локальная переменная, скажем массив целых на 100000 байт, функция рекурсивная, как кончится память догадаешься?
К>Или у тебя своя терминология и локальная переменная только на стеке? но, надеюсь, ты в курсе, что стек вещь не бесконечная?
Смею вас уверить, что нехватка стека что в C++, что в C это смертельно, правда можно попытаться что-то сделать, но платформо зависимое.
P.S.
никто из знакомых мне программистов не выделит на стеке столько.
MShura wrote: > Нормальный подход. > Если в условиях задачи разрешено использовать структурные исключения, то > можно сделать через __try/__finally
Ну так это и есть ручная эмуляция исключений.
В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды возврата.
MShura wrote:
>> > R> Разместить его на стеке? >> > Обычно это дополнительная (неуправляеммая вами) переменная, которая >> > используется для выяснения вызывался конструктор или нет. > _>Ты о чём? Зачем это выяснять? Вызов конструктора (если он есть!) > происходит в том месте, где поставлена переменная. Т.е. > А если возврат из функции произошел раньше вызова конструктора?
Он не вызовется. А ты что думал?
> Память для локальных переменных обычно выделяется при входе в функцию, > т.е. даже для того, объекта который будет проинициалирован позже память > уже выделена.
Как в С, так и в С++. И что?
> При раскрутке стека необходимо знать был ли проинициализорован объект с > нетривиальным деструктором.
Я привёл два листинга на С и С++ идентичные по коду.
А теперь мне покажи код на С, в котором будет нетривиальный деструктор (точнее его эмуляция) и кидание исключений
(точнее их эмуляция). Вот и будем их сравнивать, а пока фигню говоришь.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, MShura, Вы писали:
R>>Рассмотрим функцию на С:
MS>Одна точка входа и одна точка выхода -> наиболее распространенный стиль программирования. MS>Примеры можно посмотреть в Linux или в Windows (DDK).
>> Нормальный подход. >> Если в условиях задачи разрешено использовать структурные исключения, то >> можно сделать через __try/__finally C>Ну так это и есть ручная эмуляция исключений.
C>В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды возврата.
Не вижу разницы если проект на C использует структурные исключения вместо кодов возврата.
C++ вызывает throw а в C RaiseException.
Если вы про new vs malloc, то элементарно сделать, чтобы malloc кидал структурное исключение.
Писанины больше, но и вся разница.
Кроме того, в структурных исключениях есть возможность продолжить выполнение с места исключения.
Очень удобно при формировании буферов неопределенной заранее длины.
Обычная задача оптимизации (как быстрее реализовать switch по таблице ссылок или прямым перебром — при небольшов варианте выбора прямой перебор быстрее).
Очень часто нет необходимости делать дополнительные проверки перед освобождением ресурсов.
Как показал сам Cyberax можно сделать несколько меток в конце функции (если ресурсы захватываются последовательно а именно так и происходит в большинстве функций), что убирает необходимость в дополнительных проверках.
Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle все равно проверяется перед вызовом CloseHandle.
(Хотя можно использовать full trusted обертку, но это редкость)
Если у Вас обертка над указателем, то написав delete компилятор вставляет код проверки на NULL, даже если вы как-то убедите его не делать этой проверки, то вызов функции OS для особождения памяти опять проверит указатель на NULL.
Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, что современные компиляторы умеют нивелировать косвенный вызов функции, что уж говорить об обычном ветвлении. К тому же есть подсказки компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.
Одним словом я бы не стал категорично заявлять, что код освобождения ресурсов в C больше оного в C++.
, что то, что делает > С++ автоматически, тебе придётся делать > _>тоже самое вручную, к тому же только хуже, т.к. у тебя нет контроля > стека, какой есть у С++ компилятора. > _>С++ лишь увеличивает размер бинарника под таблицы раскрутки, а в С будет > > _>дополнительный исполняемый код, что замедлит в итоге. > <http://rsdn.ru/forum/?mid=2059458>
> > Обычная задача оптимизации (как быстрее реализовать switch по таблице > ссылок или прямым перебром — при небольшов варианте выбора прямой > перебор быстрее).
Хм?..
> Очень часто нет необходимости делать дополнительные проверки перед > освобождением ресурсов. > Как показал сам Cyberax можно сделать несколько меток в конце функции > (если ресурсы захватываются последовательно а именно так и происходит в
Если не используются исключения. В С++ их тоже можно отключить.
> большинстве функций), что убирает необходимость в дополнительных проверках.
Не делай доп проверки, что напишешь в деструкторе то и будет.
> Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle > все равно проверяется перед вызовом CloseHandle.
Да, и в чём отличие от С++?
> (Хотя можно использовать full trusted обертку, но это редкость) > Если у Вас обертка над указателем, то написав delete компилятор > вставляет код проверки на NULL, даже если вы как-то убедите его не > делать этой проверки, то вызов функции OS для особождения памяти опять > проверит указатель на NULL.
Причём тут функции ОС и С vs С++?
> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, > что современные компиляторы умеют нивелировать *косвенный* вызов > функции, что уж говорить об обычном ветвлении. К тому же есть подсказки > компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.
Да, заоптимайзить можно. Но причём тут С vs С++?
> Одним словом я бы не стал категорично заявлять, что код освобождения > ресурсов в C больше оного в C++.
В лучшем случае такой же, но никак не меньше. За счёт чего может быть меньше?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: Скорость работы с использованием классов и без
Здравствуйте, remark, Вы писали: R>Но большинство других функций не принимают размер.
Как правило, это те функции, которые не выиграют от знания размера. У них алгоритм устроен так, что последовательное сканирование их вполне устраивает.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
MShura wrote: > C>Ну так это и есть ручная эмуляция исключений. > C>В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды > возврата. > Не вижу разницы если проект на C использует структурные исключения > вместо кодов возврата.
Для SEH нужно делать настройки каждого фрейма функции. Для исключений
С++ — необязательно.
> C++ вызывает throw а в C RaiseException. > Если вы про new vs malloc, то элементарно сделать, чтобы malloc кидал > структурное исключение. > Писанины больше, но и вся разница. > Кроме того, в структурных исключениях есть возможность продолжить > выполнение с места исключения.
1. Где у нас SEH на Линуксе?
2. Как сделать SEH с zero-overhead по скорости?
MShura wrote: > Как показал сам Cyberax можно сделать несколько меток в конце функции > (если ресурсы захватываются последовательно а именно так и происходит в > большинстве функций), что убирает необходимость в дополнительных проверках. > Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle > все равно проверяется перед вызовом CloseHandle.
Я вообще-то просил сказать чем это отличается от семантики
автоматических деструкторов (ответ: почти ничем).
> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, > что современные компиляторы умеют нивелировать *косвенный* вызов > функции, что уж говорить об обычном ветвлении. К тому же есть подсказки > компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.
Ну тогда какие вопросы к С++, который просто при инициализации объекта
устанавливает флаг?
> Одним словом я бы не стал категорично заявлять, что код освобождения > ресурсов в C больше оного в C++.
Больше. В С++ с умными указателями тот же код:
>> >> Обычная задача оптимизации (как быстрее реализовать switch по таблице >> ссылок или прямым перебром — при небольшов варианте выбора прямой >> перебор быстрее). _>Хм?..
Это я к тому, что можно реализовать такой вариет освобождения ресурсов.
Иногда в больших функция имеет смысл.
void Func()
{
int res = -1;
char* a, *b;
a = (char*)malloc( 100 );
if ( NULL == a )
goto Exit;
res = 0;
b = (char*)malloc( 100 );
if ( NULL == b )
goto Exit;
res = 1;
err = Func2( a, b );
Exit:
switch( res )
{
case 1: free( b );
case 0: free( a );
}
}
>> Очень часто нет необходимости делать дополнительные проверки перед >> освобождением ресурсов. >> Как показал сам Cyberax можно сделать несколько меток в конце функции >> (если ресурсы захватываются последовательно а именно так и происходит в _>Если не используются исключения. В С++ их тоже можно отключить.
Если отлючить исключения C++, тогда производительность C++ будет приближаться к производительности C.
Только в этом случае.
>> большинстве функций), что убирает необходимость в дополнительных проверках. _>Не делай доп проверки, что напишешь в деструкторе то и будет.
>> Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle >> все равно проверяется перед вызовом CloseHandle. _>Да, и в чём отличие от С++?
>> (Хотя можно использовать full trusted обертку, но это редкость) >> Если у Вас обертка над указателем, то написав delete компилятор >> вставляет код проверки на NULL, даже если вы как-то убедите его не >> делать этой проверки, то вызов функции OS для особождения памяти опять >> проверит указатель на NULL. _>Причём тут функции ОС и С vs С++?
Вышесказанное было приведено к тому, что помимо "явных" проверок перед освобождением ресурсов будут многочисленные и даже недешевые дополнительные проверки.
>> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, >> что современные компиляторы умеют нивелировать *косвенный* вызов >> функции, что уж говорить об обычном ветвлении. К тому же есть подсказки >> компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу. _>Да, заоптимайзить можно. Но причём тут С vs С++?
Это к вариантам освобождения switch() vs "одна переменная для каждого ресурса"
>> Одним словом я бы не стал категорично заявлять, что код освобождения >> ресурсов в C больше оного в C++. _>В лучшем случае такой же, но никак не меньше. За счёт чего может быть меньше?
Имелось в в виду не написанный, а сгенеренный код.
>> Как показал сам Cyberax можно сделать несколько меток в конце функции >> (если ресурсы захватываются последовательно а именно так и происходит в >> большинстве функций), что убирает необходимость в дополнительных проверках. >> Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle >> все равно проверяется перед вызовом CloseHandle. C>Я вообще-то просил сказать чем это отличается от семантики C>автоматических деструкторов (ответ: почти ничем).
>> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, >> что современные компиляторы умеют нивелировать *косвенный* вызов >> функции, что уж говорить об обычном ветвлении. К тому же есть подсказки >> компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу. C>Ну тогда какие вопросы к С++, который просто при инициализации объекта C>устанавливает флаг?
Отвечаю на два вопроса.
В C можно никаких дополнительных переменных (неявных) не заводить.
>> Одним словом я бы не стал категорично заявлять, что код освобождения >> ресурсов в C больше оного в C++. C>Больше. В С++ с умными указателями тот же код: C>
C>Все! Причем нельзя забыть поставить cleanup в конце.
Конечно код написанный программистом на C++ будет меньше в текстовом виде, но больше в двоичном.
пример:
#include <memory>
using namespace std;
void FuncCpp( auto_ptr<char>& a, auto_ptr<char>& b );
void TestCpp()
{
auto_ptr<char> a ( new char [100] );
auto_ptr<char> b ( new char [100] );
FuncCpp( a, b );
}
#include <errno.h>
unsigned FuncC( char* a, char* b );
int TestC()
{
int err = -ENOMEM;
char* a, *b;
a = (char*)malloc( 100 );
if ( NULL == a )
goto end1;
b = (char*)malloc( 100 );
if ( NULL == b )
goto end2;
err = FuncC( a, b );
free( b );
end2:
free( a );
end1:
return err;
}
Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог
функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И asm данной функции на
С++ получился вообще без условных переходов, в отличие от С. Дополнительный код будет выполнятся только при
возникновении исключений (а по замыслу это редкие ситуации в С++).
cl /O2 /FAs /EHs
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
_>Лажа какая-то. Вот мой асм:
...
Этот листинг полностью повторяет то, что я привел.
_>Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог _>функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И asm данной функции на _>С++ получился вообще без условных переходов, в отличие от С. Дополнительный код будет выполнятся только при _>возникновении исключений (а по замыслу это редкие ситуации в С++).
То что дополнительных переходов нет это конечно хорошо.
Чуть расширьте пример (анализ содержимого в буфферах) и количество дополнительных переходов нивелируется количеством необходимых переходов.
Здравствуйте, kan_izh, Вы писали:
_>Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог _>функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И asm данной функции на _>С++ получился вообще без условных переходов, в отличие от С. Дополнительный код будет выполнятся только при _>возникновении исключений (а по замыслу это редкие ситуации в С++).
Полностью поддерживаю, что код на С++ с исключениями быстрее аналогичного на С изрезаного кучей if-ов.
Если функция с одним if-ом, то С, конечно быстрее, но если взять более сложный/реальный пример с глубиной вызовов порядка 10, то С++ с исключенями делает С с if'ами.
Читаемость и поддерживаемость кода на С — это отдельный момент. Давайте представим, что в функцию на С, которую MShura привёл здесь
, надо добавить выделение ещё нескольких ресурсов, причём часть из них выделяется не всегда, а при некотором условии. Уууух, У меня волосы дыбом встали
И для контраста представим это код на С++. Это уже само по себе огромный плюс в сторону С++, даже если при этом скорость бы была ниже (хотя она ещё и выше).
MShura wrote:
> То что дополнительных переходов нет это конечно хорошо. > Чуть расширьте пример (анализ содержимого в буфферах) и количество > дополнительных переходов нивелируется количеством необходимых переходов. > > Можно конечно возразить, что пример надуман. > Тогда милости просим сюда: > <http://rsdn.ru/Forum/Message.aspx?mid=1469428&only=1>
при простом включении опции "enable exception handling"
Считай, что вставились проверки в каждый "new". А они были до? Надо сравнивать "простое включение" с расстановкой по
всему коду явных проверок каждого malloc и прочих функций, могущих кинуть исключение... А то получилось сравнение кода вида:
MShura wrote: > Считаем: > Код функции TestC: 0x4A > Код Функции TestCpp: 0xCE-0x60 = 0x6E > auto_ptr<char>::~auto_ptr<char> : 0x60-0x56 = 0xA > два освободителя 0xDE-0xCE = 0x10 > код раскрутки стека: 0xE3 — 0xDE = 5 > таблицы: 0x110 — 0xE8 = 0x28
А теперь считаю я:
cyberax@scblinux:~/compare$ gcc --version
gcc (GCC) 4.1.2 20060729 (prerelease) (Debian 4.1.1-10)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
cyberax@scblinux:~/compare$ uname -a
Linux scblinux 2.6.17.7 #3 Mon Aug 7 19:23:59 UTC 2006 x86_64 GNU/Linux
cyberax@scblinux:~/compare$ gcc -O2 -S -fPIC test.c
Здравствуйте, Cyberax, Вы писали:
C>MShura wrote: >> Считаем: >> Код функции TestC: 0x4A >> Код Функции TestCpp: 0xCE-0x60 = 0x6E >> auto_ptr<char>::~auto_ptr<char> : 0x60-0x56 = 0xA >> два освободителя 0xDE-0xCE = 0x10 >> код раскрутки стека: 0xE3 — 0xDE = 5 >> таблицы: 0x110 — 0xE8 = 0x28 C>А теперь считаю я:
... C>Итого имеем: код на С++ занимает меньше места в исходном виде и C>выполнятется быстрее Сшного кода.
Хороший ответ. Однако вы не подсчитали размеры.
Я сделаю это за Вас (gcc версии 4.0.2):
TestC: 0x60
TestCpp: 0x4B
Обвязка TestCpp: 0xAC
Усложним задачу?
#include <memory>
using namespace std;
void FuncCpp( auto_ptr<char>& a, auto_ptr<char>& b, int );
void TestCpp()
{
auto_ptr<char> a ( new char [100] );
auto_ptr<char> b ( new char [100] );
try
{
FuncCpp( a, b, 0 );
}
catch( ... )
{
FuncCpp( a, b, 1 );
}
}
#include <errno.h>
unsigned FuncC( char* a, char* b, int );
int TestC()
{
int err = -ENOMEM;
char* a, *b;
a = (char*)malloc( 100 );
if ( NULL == a )
goto end1;
b = (char*)malloc( 100 );
if ( NULL == b )
goto end2;
err = FuncC( a, b, 0 );
if ( 0 != err )
err = FuncC( a, b, 1 );
free( b );
end2:
free( a );
end1:
return err;
}
Подсчитайте теперь.
При тех-же условиях у меня получилось
0x80 vs 0xAC + 0x9C
MShura wrote: > C>А теперь считаю я: > ... > C>Итого имеем: код на С++ занимает меньше места в исходном виде и > C>выполнятется быстрее Сшного кода. > Хороший ответ. Однако вы не подсчитали размеры. > Я сделаю это за Вас (gcc версии 4.0.2): > TestC: 0x60 > TestCpp: 0x4B > Обвязка TestCpp: 0xAC
Ну так я говорил, что ускорение покупается ценой увеличения размера
бинариков. Однако, линкер распологает секции с информациях о EH в
отдельную область exe-шника, так что при нормальной работе это не влияет
на cache locality.
> Усложним задачу?
Для С++:
А тут у нас появились ветвления. Причем предиктор вполне может в первое
прохождение кода их предсказать неправильно.
> Подсчитайте теперь. > При тех-же условиях у меня получилось > 0x80 vs 0xAC + 0x9C
Ну да, получается больший размер.
У меня для С++:
.text = b5
.gcc_except_table = 28
Имеем DD (221)
C>Итого имеем: код на С++ занимает меньше места в исходном виде и C>выполнятется быстрее Сшного кода.
Количество инструкций и ветвлений в C коде будет не больше количества инструкций и ветвлений в C++.
Да код только функции TestC больше кода TestCpp (в gcc), но уверены ли вы, что в исполняемом коде обвязка TestCpp будет помещена в другую страницу?
Если обвязка TestCpp будет располагаться рядом с самой функцией то боюсь что размер функция + обвязка имеет значение (не в пользу С++)
MShura wrote: > C>Итого имеем: код на С++ занимает меньше места в исходном виде и > C>выполнятется быстрее Сшного кода. > Количество инструкций и ветвлений в C коде будет не больше количества > инструкций и ветвлений в C++.
Будет. И есть. Посчитай количество ветвлений в коде на С++ (подсказываю:
ноль).
Табличный EH позволяет исполнять код с исключениями без всяких накладных
расходов по скорости.
> Да код только функции TestC больше кода TestCpp (в gcc), но уверены ли > вы, что в исполняемом коде обвязка TestCpp будет помещена в другую страницу?
Уверен. Линкер и компилиятор не дураки писали и про локальность кэша знают.
>> C>Итого имеем: код на С++ занимает меньше места в исходном виде и >> C>выполнятется быстрее Сшного кода. >> Количество инструкций и ветвлений в C коде будет не больше количества >> инструкций и ветвлений в C++. C>Будет. И есть. Посчитай количество ветвлений в коде на С++ (подсказываю: C> ноль).
А как реализован operator new?
Уж не так ли?
void* operator new( size_t n )
{
void* p = malloc( n );
if ( NULL == p )
throw std::bad_alloc();
return p;
}
Если реализован именно так, то в C коде сравнений столько же, а ветвлений меньше (вызов функции есть ветвление).
C>Табличный EH позволяет исполнять код с исключениями без всяких накладных C>расходов по скорости.
Да в ggc красиво реализовано try/catch
>> Да код только функции TestC больше кода TestCpp (в gcc), но уверены ли >> вы, что в исполняемом коде обвязка TestCpp будет помещена в другую страницу? C>Уверен. Линкер и компилиятор не дураки писали и про локальность кэша знают.
Для этого надо бы посмотреть карту готового (желательно немаленького) бинарника и убедиться что все обработчики лежат рядышком и в далеке от основного кода.
Здравствуйте, MShura, Вы писали:
>>> C>Итого имеем: код на С++ занимает меньше места в исходном виде и >>> C>выполнятется быстрее Сшного кода. >>> Количество инструкций и ветвлений в C коде будет не больше количества >>> инструкций и ветвлений в C++. C>>Будет. И есть. Посчитай количество ветвлений в коде на С++ (подсказываю: C>> ноль).
MS>А как реализован operator new? MS>Уж не так ли?
MS>
MS>void* operator new( size_t n )
MS>{
MS> void* p = malloc( n );
MS> if ( NULL == p )
MS> throw std::bad_alloc();
MS> return p;
MS>}
MS>
MS>Если реализован именно так, то в C коде сравнений столько же, а ветвлений меньше (вызов функции есть ветвление).
Дело не в этом. В С++ коде будет один if в operator new, а потом исключение пролетит возможно пару десятков функций вверх (вполне возможно при современном уровне сложности ПО) до обработчика, а в С коде все эти пара десятков функций будут забиты if'ами, которые будут выполняться всегда, а не только когда произошла ошибка.
Это не говоря о том, что, даже если все программисты патологически прилежные и не забывают писать все if'ы, вместе с производительностью значительно снижается читаемость и понятность кода.
Здравствуйте, Cyberax, Вы писали:
>> Подсчитайте теперь. >> При тех-же условиях у меня получилось >> 0x80 vs 0xAC + 0x9C C>Ну да, получается больший размер. C>У меня для С++: C>.text = b5 C>.gcc_except_table = 28 C>Имеем DD (221)
C>Для С: C>.text = 8c (140)
Моё мнение по этому поводу такое.
Для настольных и тем более для серверных систем размер диска и ОП перестали быть узким местом. Касательно ОП я имею в виду те изменения размера, о которых идёт речь. А вот ЦП зачастую становится узким местом, особенно для серверных систем.
Поэтому я бы сходу променял несколько мегабайт бинарника на увеличившуюся производительность. Особенно, если то, что написал Cyberax по поводу cache locality, действительно имеет место.
Без разницы бинарник занимает 10 или 15 метров, если при работе он всё равно съедает несколько сот метров.
Единственная оговорка — встроенные системы. Но тут уже надо смотреть конкретный вариант. Общего решения нет. Потому как и ставить более производительный микропроцессор, и ставить микропроцессор с большим объёмом ПЗУ денег стоит. Или параметры процессора просто жестко оговорены.
Поэтому мне более интересна производительность. А при моих тестах код с исключениями работает быстрее кода с кучей if'ов (при достижении некоторой пороговой, не очень большой, вложенности вызовов функций и их количества. а количество функций и вложенность сейчас обычно велика и только растёт со временем развития системы).
Здравствуйте, MShura, Вы писали:
MS>Усложним задачу?
Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, MShura, Вы писали:
MS>>Усложним задачу? S>Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.
Да, я предлагаю усложить так, что будем выделять не массив char'ов, а массив объектов, у которых есть нетривиальный конструктор и деструктор. Соответственно в С выделяем массив структур и надо вызывать функцию init()/deinit() для каждой структуры
R>Моё мнение по этому поводу такое. R>Для настольных и тем более для серверных систем размер диска и ОП перестали быть узким местом. Касательно ОП я имею в виду те изменения размера, о которых идёт речь. А вот ЦП зачастую становится узким местом, особенно для серверных систем. R>Поэтому я бы сходу променял несколько мегабайт бинарника на увеличившуюся производительность. Особенно, если то, что написал Cyberax по поводу cache locality, действительно имеет место.
Боюсь вас огорчить по поводу cache locality.
Я не знаю как у Cyberax, но в коде, который сгенерил мой gcc 4.0.2 обработчик лежит в том же сегменте, что и основная функция.
Линкер ну никак не сможет его поместить подальше от основного кода.
MS>>Усложним задачу? S>Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.
С увеличением количества объектов C++ будет отставать всё больше и больше.
Re[12]: Скорость работы с использованием классов и без
Здравствуйте, Cyberax, Вы писали:
C>В новых процессорах есть предсказатель косвенных переходов. Погугли по словам "indirect branch prediction".
Для вызова через VTable необходимо 2 косвенных чтения (1й — читаем адрес таблицы, и только 2й — вызов функции).
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[13]: Скорость работы с использованием классов и без
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, Cyberax, Вы писали:
C>>В новых процессорах есть предсказатель косвенных переходов. Погугли по словам "indirect branch prediction".
GN>Для вызова через VTable необходимо 2 косвенных чтения (1й — читаем адрес таблицы, и только 2й — вызов функции).
чтения да два, но переход то один.
Re[14]: Скорость работы с использованием классов и без
Здравствуйте, FR, Вы писали:
FR>чтения да два, но переход то один.
В принципе, да... как я понимаю, предсказатель говорит: команда косвенного перехода, расположенная по такому-то адресу, перейдёт туда-то. То есть можно тупо откинуть анализ поинтера на VTable.
А потом вспоминаем пример полиморфизма из книжки Sprite.Draw(). И потомков у этого класса — 68. Все они обрабатываются в цикле, при рендеринге сцены в аркадной игрушке... А конвеер у последних процев очень уж свехдлинный и его сброс далеко не бесплатен
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[15]: Скорость работы с использованием классов и без
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, FR, Вы писали:
FR>>чтения да два, но переход то один.
GN>В принципе, да... как я понимаю, предсказатель говорит: команда косвенного перехода, расположенная по такому-то адресу, перейдёт туда-то. То есть можно тупо откинуть анализ поинтера на VTable.
Угу, нужно только помнить с какой точки и куда ходили.
GN>А потом вспоминаем пример полиморфизма из книжки Sprite.Draw(). И потомков у этого класса — 68. Все они обрабатываются в цикле, при рендеринге сцены в аркадной игрушке... А конвеер у последних процев очень уж свехдлинный и его сброс далеко не бесплатен
Плохой пример на фоне Sprite.Draw() затраты и на вызов виртуальной функции (и не только виртуальной, но и даже функции из скрипта) и на сброс конвеера равны нулю
Re[16]: Скорость работы с использованием классов и без
Здравствуйте, FR, Вы писали:
FR>Плохой пример на фоне Sprite.Draw() затраты и на вызов виртуальной функции (и не только виртуальной, но и даже функции из скрипта) и на сброс конвеера равны нулю
Вот об этом я и говорю. Зачем какой-то предиктор, который еще и тормозит временами
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Есть такие проблемы у компилятора. Решаются (иногда) при помощи /GL (WPO или link-time code generation) или (практически всегда) __forceinline. Однако кто же будет писать это в стандартной библиотеке?
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, Cyberax, Вы писали:
C>Для SEH нужно делать настройки каждого фрейма функции. Для исключений С++ — необязательно.
Угу, у *них — не обязательно, потому что:
C>1. Где у нас SEH на Линуксе? C>2. Как сделать SEH с zero-overhead по скорости?
Никак, у SEH задачи несколько шире, чем у С++ исключений. Тот же функционал при помощи сигналов даст бОльший оверхед.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, Cyberax, Вы писали:
C>Линкер и компилиятор не дураки писали и про локальность кэша знают.
Задача решаема только для JIT. У разных CPU разные характиристики кеша.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
gear nuke wrote: > C>Линкер и компилиятор не дураки писали и про локальность кэша знают. > Задача решаема только для JIT. У разных CPU разные характиристики кеша.
Ну почему же, можно поступить и как Linux Gentoo — компилировать все на
машине пользователя с оптимизациями под точную модель процессора.
Здравствуйте, Cyberax, Вы писали:
C>>>Линкер и компилиятор не дураки писали и про локальность кэша знают. >> Задача решаема только для JIT. У разных CPU разные характиристики кеша. C>Ну почему же, можно поступить и как Linux Gentoo — компилировать все на C>машине пользователя с оптимизациями под точную модель процессора.
Хм, да... поторопился я Задача так же решаема и в некоторых других редких случаях.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth