Скорость работы с использованием классов и без
От: Kokoban  
Дата: 03.08.06 02:00
Оценка: :))) :))
Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.
Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
Интересно как дело обстоит когда мы используем только наследование?
Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?

Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.
Re: Скорость работы с использованием классов и без
От: FR  
Дата: 03.08.06 04:56
Оценка: 5 (3)
Здравствуйте, 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;
}


PUBLIC    _main
EXTRN    _printf:NEAR
; Function compile flags: /Ogty
_TEXT    SEGMENT
_argc$ = 8                        ; size = 4
_argv$ = 12                        ; size = 4
_main    PROC NEAR

; 25   : printf("%d\n", Test().add(1, 2));

    push    126                    ; 0000007eH
    push    OFFSET FLAT:$SG633
    call    _printf
    add    esp, 8

; 26   : return 0;

    xor    eax, eax

; 27   : }

    ret    0
_main    ENDP


(c) VC8
Re[2]: Скорость работы с использованием классов и без
От: Kokoban  
Дата: 03.08.06 05:58
Оценка:
Наверно это компилятор С++ оптимизировал так код, что даже числа сам сложил!
А в целом логично что методы классов ничем не отличаются от обычных функций, а поля от глобальных переменных. Вообщем этого я и ожидал.
Re: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 06:50
Оценка: 1 (1) +2
Kokoban wrote:
> Типичное мнение старых С-программистов — то, что использование С++
> классов тормозит работу программы.
Не надо слушать таких программистов.

Во-первых, значительную часть виртуальных вызовов компилятор
замечательно соптимизирует в статические.
Во-вторых, в новых процессорах есть специальные аппаратные оптимизации
косвенного вызова.
В-третьих, можно замечательно использовать ООП без виртуальных функций.
В качестве примера можно взять STL.

> Понятно, что использование таблиц виртуальных функций влияет на

> производительность программ, но как сильно?
Очень незначительно.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
От: bkat  
Дата: 03.08.06 07:03
Оценка: 1 (1) +2
Здравствуйте, Kokoban, Вы писали:

K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.

K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?

Сравнивать языки есть смысл только на общем подмножестве конструкций языка.
Нету в С виртуальный методов, потому нет смысла сравнивать виртуальные методы в С++
с тем, чего нету в С. Иначе надо сравнивать виртуальные методы в С++
с некой самопольной эмуляцией виртуальных методов средствами голого С.
Re: Скорость работы с использованием классов и без
От: DerBober США  
Дата: 03.08.06 09:38
Оценка:
Здравствуйте, Kokoban, Вы писали:

K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.


K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.


Основной проблемой считались не тормоза виртуальных функций, а увеличение объемов программы. Размер почити каждого объекта увеличивается на одно слово в котором хранится указатель на таблицу виртуальных функций. Ну и еще там всякием мелочи. Сейчас память сильно подешевела и этой проблемы вроде как нет.
Скорость больше зависит от того как напишешь, а не на чем.
Re: Скорость работы с использованием классов и без
От: Андрей Хропов Россия  
Дата: 03.08.06 10:39
Оценка: 33 (3) +1
Здравствуйте, Kokoban, Вы писали:

K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.

K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
K>Интересно как дело обстоит когда мы используем только наследование?
K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?

K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.


Почитай что ли здесь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Скорость работы с использованием классов и без
От: MShura  
Дата: 03.08.06 11:08
Оценка: 12 (1)
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 будет NULL
void 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]: Скорость работы с использованием классов и без
От: bkat  
Дата: 03.08.06 11:28
Оценка:
Здравствуйте, MShura, Вы писали:

Не вопрос, что это все можно реализовывать ручками...
Но, как и любая ручная реализация, это решение будет подвержено ошибкам и будут тратиться усилия на поддержку
всей этой ручной инфраструктуры в нормальном состоянии.
В С++ это делает компилятор...

MS>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету.

MS>Попробуйте в C++ виртуальности подменить виртуальную функцию.

У меня видимо не такие задачи как у тебя.
Мне еще ни разу не требовалось подменять виртуальные функции на лету.
Ну либо это решалось какими-то более явными методами.
Re[3]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 11:29
Оценка: +1
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]: Скорость работы с использованием классов и без
От: MShura  
Дата: 03.08.06 11:45
Оценка:
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]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 12:16
Оценка: +3
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]: Скорость работы с использованием классов и без
От: MShura  
Дата: 03.08.06 12:45
Оценка:
..
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]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 12:51
Оценка:
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]: Скорость работы с использованием классов и без
От: MShura  
Дата: 03.08.06 13:48
Оценка:
>> C>Ага, это надо сравнивать его НА КАЖДЫЙ вызов. В результате вместо кода
>> C>получим макароны.
>> Не напоминает ли Вам это спор указатель vs ссылка?
C>А какой тут спор?
Если есть выбор использовать указатель или ссылку, то что лучше использовать.
Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок.
Я вижу такую аналогию, что таблица функций сгенеренная компилятором никогда не содержит пустые элементы, поэтому их можно вызывать без проверки. Ручная таблица и есть ручная.

C>Если элементы в таблице функций по дизайну могут принимать NULLовое

C>значение, то их все перед вызовом надо проверять. А это медленно.
Если предполагается дальнейшее расширение интерфейса, то что быстрее:
— вызвать без проверки виртуальную функцию, проверить значение на "не реализовано", принять решение
— проверить на NULL указатель на функцию, принять решение

C>А если только некоторые функции могут быть NULL'ами, то почему бы их не

C>вынести в один интерфейс?
Такой интерфейс легко расширяется.
Старый код продолжает работать ничего не зная о новых методах.

>> C>Похоже на неоправданый хак. Для получения информации проще было бы

>> C>создать дополнительный интерфейс.
>> Этот подход — результат эволюции UNIX/Linux OS.
C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас
C>лень доставать мануалы.
Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные заменить на заглушки возвращающие определенный код?
если понадобиться расширить vfs (а оно потихоньку расширяется), то придется переписывать старые драйвера?
(Т.е. добавлять пустые заглушки)
Re[9]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 14:36
Оценка:
MShura wrote:
> C>А какой тут спор?
> Если есть выбор использовать указатель или ссылку, то что лучше
> использовать.
> Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок.
Ну вообще-то указатель и ссылка — это разные вещи. В частности,
для ссылки гарантируется, что она не NULL и над ней нельзя делать
адресную арифметику.

> C>Если элементы в таблице функций по дизайну могут принимать NULLовое

> C>значение, то их все перед вызовом надо проверять. А это медленно.
> Если предполагается дальнейшее расширение интерфейса, то что быстрее:
> — вызвать без проверки виртуальную функцию, проверить значение на "не
> реализовано", принять решение
> — проверить на NULL указатель на функцию, принять решение
Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы.

Ты еще не забудь, что тебе надо проверять ВСЕ функции. Либо надеяться,
что они будут реализованы.

> C>А если только некоторые функции могут быть NULL'ами, то почему бы их не

> C>вынести в один интерфейс?
> Такой интерфейс легко расширяется.
> Старый код продолжает работать ничего не зная о новых методах.
Не понял.
struct IMalloc
{
    virtual void* alloc(size_t)=0;
    virtual void  free(void*)=0;
    virtual void* realloc(void*, size_t)=0;
};
struct IMapingMalloc : public IMalloc
{
    virtual void mmap(...)=0;
};

Старые клиенты будут замечательно работать со старым IMalloc'ом (даже
если это IMapingMalloc), ничего не зная, про новый интерфейс.

> C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас

> C>лень доставать мануалы.
> Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные
> заменить на заглушки возвращающие определенный код?
Нет, там у драйвера была функция, которая возвращала битовую маску с
возможностями драйвера.

> если понадобиться расширить vfs (а оно потихоньку расширяется), то

> придется переписывать старые драйвера?
> (Т.е. добавлять пустые заглушки)
Вообще-то, для новых функций обычно делают новые интерфейсы.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[10]: Скорость работы с использованием классов и без
От: MShura  
Дата: 03.08.06 15:07
Оценка:
>> C>А какой тут спор?
>> Если есть выбор использовать указатель или ссылку, то что лучше
>> использовать.
>> Кто-то на стороне указателей (я в том числе), кто-то не мыслит без ссылок.
C>Ну вообще-то указатель и ссылка — это разные вещи. В частности,
C>для ссылки гарантируется, что она не NULL и над ней нельзя делать
C>адресную арифметику.
Ссылка реализуется через указатель точно также, как виртуальные функции реализуются через таблицу функций.
указатель может быть NULL ссылка нет, указатель в таблице функций может быть NULL, указатель в таблице виртуальных функций нет.
По аналогии можно считать что в таблице виртуальных функций хранятся ссылки на функции.


>> C>Если элементы в таблице функций по дизайну могут принимать NULLовое

>> C>значение, то их все перед вызовом надо проверять. А это медленно.
>> Если предполагается дальнейшее расширение интерфейса, то что быстрее:
>> — вызвать без проверки виртуальную функцию, проверить значение на "не
>> реализовано", принять решение
>> — проверить на NULL указатель на функцию, принять решение
C>Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы.
Не согласен.
Как можно оптимизировать вызов виртуальной функции не зная точно типа объекта (конструкторы/деструкторы не рассматриваем)
Т.е. нужно сформировать аргументы, сделать call, проверить с определенным (скорее всего ненулевым) значением (проверка на нуль — самая простая).
Однозначно дольше.

C>Ты еще не забудь, что тебе надо проверять ВСЕ функции. Либо надеяться,

C>что они будут реализованы.
Это верно.


>> C>А если только некоторые функции могут быть NULL'ами, то почему бы их не

>> C>вынести в один интерфейс?
>> Такой интерфейс легко расширяется.
>> Старый код продолжает работать ничего не зная о новых методах.
C>Не понял.
C>
C>struct IMalloc
C>{
C>    virtual void* alloc(size_t)=0;
C>    virtual void  free(void*)=0;
C>    virtual void* realloc(void*, size_t)=0;
C>};
C>struct IMapingMalloc : public IMalloc
C>{
C>    virtual void mmap(...)=0;
C>};
C>

C>Старые клиенты будут замечательно работать со старым IMalloc'ом (даже
C>если это IMapingMalloc), ничего не зная, про новый интерфейс.

>> C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас

>> C>лень доставать мануалы.
>> Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные
>> заменить на заглушки возвращающие определенный код?
C>Нет, там у драйвера была функция, которая возвращала битовую маску с
C>возможностями драйвера.

>> если понадобиться расширить vfs (а оно потихоньку расширяется), то

>> придется переписывать старые драйвера?
>> (Т.е. добавлять пустые заглушки)
C>Вообще-то, для новых функций обычно делают новые интерфейсы.

схема немножко другая: Клиент один, серверов много.

Есть интерфес
struct IFs
{
  virtual int open(int) = 0;
  virtual void  close(int) = 0;
};


Ваш код его реализует и регистрирует его в системе так, что клиенту становится доступна функци module_init()
struct IMyFs : public IFs
{
  virtual int open(int);
  virtual void  close(int);
};
IMyFs* module_init();


Код клиента:
// Для каждого зарегистрированного модуля (сервера)
IFs* fs = module_init();
fs->open(3);



Теперь потребовалось расширить IFs
struct IFs
{
  virtual int open(int) = 0;
  virtual void  close(int) = 0;
  virtual int open(char*) = 0;
};


Нет смысла менять код старых реализаций IFs.
Меняем только необходимые реализации.

Код клиента:
// Для каждого зарегистрированного модуля (сервера)
IFs* fs = module_init();
if ( NULL != fs->open2 )
  fs->open2( "/tmp" );
else
  fs->open(3);
Re[11]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 15:55
Оценка:
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]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 03.08.06 15:58
Оценка:
MShura wrote:
> C>Вероятно, одинаково. Новые процессоры оптимизируют косвенные вызовы.
> Не согласен.
> Как можно оптимизировать вызов виртуальной функции не зная точно типа
> объекта (конструкторы/деструкторы не рассматриваем)
> Т.е. нужно сформировать аргументы, сделать call, проверить с
> определенным (скорее всего ненулевым) значением (проверка на нуль —
> самая простая).
> Однозначно дольше.
В новых процессорах есть предсказатель косвенных переходов. Погугли по
словам "indirect branch prediction". Расходы на формирование списка
аргументов — возможны.

Хотя если код критически зависит по скорости от подобного приема — то я
бы использовал битовую маску.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[9]: Скорость работы с использованием классов и без
От: raskin Россия  
Дата: 03.08.06 19:37
Оценка: +1
MShura wrote:
>> > Этот подход — результат эволюции UNIX/Linux OS.
> C>Вроде бы в Solaris'ной VFS нулевые функции были явно запрещены. Сейчас
> C>лень доставать мануалы.
> Т.е. все драйвера должны реализовать ВСЕ нужные функции а не нужные
> заменить на заглушки возвращающие определенный код?
> если понадобиться расширить vfs (а оно потихоньку расширяется), то
> придется переписывать старые драйвера?
> (Т.е. добавлять пустые заглушки)
Не стал бы я защищать решение в ядре Linux тем, что оно избавляет от
необходимости корректировать (простым образом) код старых драйверов в
ядре при эволюции ядра... Эта необходимость есть by design, во всяком
случае, так декларируется.
Posted via RSDN NNTP Server 2.0
Re: Скорость работы с использованием классов и без
От: vdimas Россия  
Дата: 04.08.06 08:39
Оценка: 1 (1) +1
Здравствуйте, Kokoban, Вы писали:

K>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.

K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?
K>Интересно как дело обстоит когда мы используем только наследование?
K>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?

K>Очень хотелось бы услышать мнение людей по этому поводу. Может кто-нибудь даст ссылки. Заранее спасибо.


Чаще всего там, где падает скорость — это плата за безопасность. Например, вынос всех статических и стековых буферов в безопасные STL-коллекции. А те, в свою очередь, работают с кучей по-умолчанию, что не есть быстро. Если же скорость действительно критична, то применяют различные аллокаторы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 05.08.06 18:47
Оценка:
Здравствуйте, MShura, Вы писали:

MS>// Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULL


Элементарно:

struct IMalloc
{
  virtual void* Realloc()
  {
    return 0;
  }
};



MS>Точно также с помощью таблиц легко реализовать подмену "виртуальной" функции уже на лету.

MS>Попробуйте в C++ виртуальности подменить виртуальную функцию.

Тоже элеметарно:

std::auto_ptr<IMalloc> a (new AllocImpl());
// выполняем действия с одной реализацией
a.reset(new AnotherAllocImpl); // Подменяем одну (или несколько) функций в таблице
// выполняем действия с другой реализацией



Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Скорость работы с использованием классов и без
От: MShura  
Дата: 05.08.06 20:01
Оценка:
MS>>// Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULL

R>Элементарно:


R>
R>struct IMalloc
R>{
R>  virtual void* Realloc()
R>  {
R>    return 0;
R>  }
R>};
R>


Что вы хотели этим сказать?
В этом примере не 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]: Скорость работы с использованием классов и без
От: Kokoban  
Дата: 08.08.06 04:22
Оценка:
Большое спасибо всем за подробные ответы.
Re[5]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 08.08.06 04:37
Оценка:
Здравствуйте, MShura, Вы писали:

R>>Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций.

MS>Ровно столько-же сколько и их C++ аналоги.

Кажется ты говорил не о подмене функции для класса, а о подмене функции для объекта.
Считаем.
В классе С++ содержится один указатель на vtable класса (поясняю — 4 байта на 80x86).
Если ты собрался менять функции отдельно для каждого объекта, то значит у тебя каждый объект содержит свою таблицу функций. Т.е. если у объекта 10 таких функций, то таблица занимает 40 байт.

Или я что-то не так посчитал? Или ты предлагаешь какую-то другую реализацию?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 08.08.06 04:51
Оценка:
Здравствуйте, MShura, Вы писали:

MS>>>// Попробуйте реализовать такой C++ интерфейс, у которого I->Realloc будет NULL


R>>Элементарно:


R>>
R>>struct IMalloc
R>>{
R>>  virtual void* Realloc()
R>>  {
R>>    return 0;
R>>  }
R>>};
R>>


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());



Пожалуйста решение с подменой поведения, причём с большей поддержкой языка.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Скорость работы с использованием классов и без
От: MShura  
Дата: 08.08.06 10:41
Оценка:
R>>>Кстати, ты забыл упомянуть сколько будут занимать твои объекты, если в каждом будет по 10-20 таких самопальных виртуальных функций.
MS>>Ровно столько-же сколько и их C++ аналоги.

R>Кажется ты говорил не о подмене функции для класса, а о подмене функции для объекта.

R>Считаем.
R>В классе С++ содержится один указатель на vtable класса (поясняю — 4 байта на 80x86).
R>Если ты собрался менять функции отдельно для каждого объекта, то значит у тебя каждый объект содержит свою таблицу функций. Т.е. если у объекта 10 таких функций, то таблица занимает 40 байт.

R>Или я что-то не так посчитал? Или ты предлагаешь какую-то другую реализацию?


Есть таблица функций, её можно расположить где хочешь (на стеке, в куче, глобально).
Кстати в C++ создается исключительно глобальная таблица и только в const секции.
Объект содержит указатель на эту таблицу.
Создаем копию таблицы. Меняем в ней один или несколько элементов. В подопытном объекте меняем указатель на новую таблицу.
Всё.
Ровно столько же придется делать на C++, но поскольку только компилятор имеет возможность управлять таблицей функций, то придется делать еще один класс (proxy для подопытного).

Итого тоже две таблицы, но неуправляемые программистом.
Re[7]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 08.08.06 10:46
Оценка:
Здравствуйте, MShura, Вы писали:

MS>Итого тоже две таблицы, но неуправляемые программистом.


здесь
Автор: remark
Дата: 08.08.06
я привёл пример как аналогичное делают в с++



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Скорость работы с использованием классов и без
От: MShura  
Дата: 08.08.06 10:51
Оценка:
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]: Скорость работы с использованием классов и без
От: trophim Россия  
Дата: 09.08.06 00:27
Оценка:
Здравствуйте, Cyberax, Вы писали:


C>Во-вторых, в новых процессорах есть специальные аппаратные оптимизации

C>косвенного вызова.

А я в танке видимо... Про что речь? Можно чуть поподробнее? Какие оптимизации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Let it be! — Давайте есть пчелу!
Re[12]: Скорость работы с использованием классов и без
От: kan_izh Великобритания  
Дата: 09.08.06 07:59
Оценка:
Cyberax wrote:

>> Теперь потребовалось расширить IFs

[сcode]
>> struct IFs
>> {
>> virtual int open(int) = 0;
>> virtual void close(int) = 0;
>> virtual int open(char*) = 0;
>> };
[/сcode]
> Вот для этого создаешь наследника:
Не... нехорошо... а если так? Добавляем новый интерфейс и модифицируем старый (оставляя весь старый код компилябельным):

struct IFsExt : public IFs
{
    virtual int open(char*) = 0;
};
>>  struct IFs
>>  {
>>  virtual int open(int) = 0;
>>  virtual void close(int) = 0;
virtual IFsExt *getExt() {return NULL};
>>  };

Реализации getExt могут просто this возвращать (если поддерживается).

>> Код клиента:

>> // Для каждого зарегистрированного модуля (сервера)
>>  IFs* fs = module_init();
>>  if ( NULL != fs->open2 )
>>  fs->open2( "/tmp" );
>>  else
>>  fs->open(3);

IFs *fs = module_init();
IFsExt *fsExt = fs->getExt();
if(fsExt)//всего одна проверка, затем смело используем весь интерфейс без лишних проверок.
{
   fsExt->open(/"tmp");
   fsExt->close(5);
}
else
{
   fs->open(3);
   fs->close(5);
}
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 09.08.06 14:21
Оценка:
trophim wrote:
> C>Во-вторых, в новых процессорах есть специальные аппаратные оптимизации
> C>косвенного вызова.
> А я в танке видимо... Про что речь? Можно чуть поподробнее? Какие
> оптимизации?
Запоминается куда в прошлый раз делалось косвенное обращение. Почитайте
про предиктор в новых Intel Core.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 10.08.06 18:42
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 10.08.06 19:22
Оценка: +1
Геннадий Васильев 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]: Скорость работы с использованием классов и без
От: FR  
Дата: 10.08.06 19:25
Оценка: +1
Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>
ГВ>void func()
ГВ>{
ГВ>  std::string s = "this is my string";
ГВ>}
ГВ>


ГВ>это два обращения к хипу на каждый вызов (конструктур/деструктор).


Именно такая и именно в VC >7.0 не вызовет ни одного обращения к хипу, строка маленька и помещается в буфер на стеке
Re[3]: Скорость работы с использованием классов и без
От: Sni4ok  
Дата: 10.08.06 20:10
Оценка:
ГВ>>
ГВ>>  std::string s = "this is my string";
ГВ>>


FR>Именно такая и именно в VC >7.0 не вызовет ни одного обращения к хипу, строка маленька и помещается в буфер на стеке


у мну под 8.0 обращение к хипу будет, поскольку s.size() == 17, а юниончик в стринге только на 16 элементов в случае std::string'а.
Re[2]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 11.08.06 07:08
Оценка: +1 :))
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, Kokoban, Вы писали:


K>>Типичное мнение старых С-программистов — то, что использование С++ классов тормозит работу программы.

K>>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?

ГВ>Не секрет, например, что на C зачастую (я не говорю — обязательно!) пишут простую обработку структуры данных одной функцией вместо нагромождения адаптеров, фасадов и прочего.


Не секрет, что программисты на С зачастую (я имею в виду практически всегда) для хранения строк используют char*, при этом для вычисления длины строки при каждом удобном и неудобном случае используют strlen(). В результате чего получается следующее:

char* request = ...;

int generateSome()
{
  char* xxx = request;
  int len = strlen(request); //1
}

send(sock, request, strlen(request), 0); //2

int generateSome2()
{
  char* xxx2 = request;
  int len2 = strlen(request); //3
}

if (strncmp(request, request2, min(strlen(request), strlen(request2))); //3 //4


Что такое strlen() Вы понимаете — перелопачивание всей памяти строки с загрузкой её в кэш из памяти и с выгрузкой из кэша других нужных данных.
Таких ненужных strlen в программе С программиста я обычно насчитываю десятки. А ничего подобного я ни разу не видел:

typedef struct
{
  char* str;
  int len;
} string;


На фоне этого расходы на VMT не заметны вообще.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Объясните глупому С++ программисту!
От: remark Россия http://www.1024cores.net/
Дата: 11.08.06 07:14
Оценка: +2
Здравствуйте, Kokoban, Вы писали:

K>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?


А как, интересно, С программист эмулирует то поведение, которое С++ получил с применением таблицы виртуальных функций ???
Он сделает это как-то эффективнее с т.з. вычислительной или ёмкостной сложности ??? У него это будет удобнее ???

Аналогично относительно других фич С++, относительно которых С программисты считают, что они замедляют программу.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Скорость работы с использованием классов и без
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 11.08.06 11:28
Оценка: +1
Здравствуйте, FR, Вы писали:

ГВ>>это два обращения к хипу на каждый вызов (конструктур/деструктор).

FR>Именно такая и именно в VC >7.0 не вызовет ни одного обращения к хипу, строка маленька и помещается в буфер на стеке

Я о другом, о том, что new/delete могут оказаться в неожиданных на первый взгляд местах и поспособствовать кое-каким заблуждениям.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: Скорость работы с использованием классов и без
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 11.08.06 11:39
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: MShura  
Дата: 11.08.06 12:29
Оценка: +1
R>Не секрет, что программисты на С зачастую (я имею в виду практически всегда) для хранения строк используют char*, при этом для вычисления длины строки при каждом удобном и неудобном случае используют strlen(). В результате чего получается следующее:

....
R>Таких ненужных strlen в программе С программиста я обычно насчитываю десятки. А ничего подобного я ни разу не видел:

R>
R>typedef struct
R>{
R>  char* str;
R>  int len;
R>} string;
R>


Как любят говорить на этом форуме: "отучаемся говорить за всех".
Посмотрите на структуру UNICODE_STRING в Windows или qstr в Linux.
Я пользуюсь ими а Вы?
Re[4]: Скорость работы с использованием классов и без
От: kan_izh Великобритания  
Дата: 11.08.06 15:43
Оценка: +1
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]: Скорость работы с использованием классов и без
От: igna Россия  
Дата: 11.08.06 16:20
Оценка: 1 (1) +1
Здравствуйте, 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.

(http://www.amazon.com/gp/product/0201309564/sr=8-6/qid=1155312739/ref=pd_bbs_6/104-6863636-3097568?ie=UTF8)


А Степанов и вовсе это самое ООП недолюбливает: An Interview with A. Stepanov
Re[5]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 14.08.06 07:20
Оценка: +1
Здравствуйте, 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. В С++ такие оптимизации обеспечиваются автоматически. Быстрый код получается при минимуме усилий.
А С приминуме усилий даёт не такой эффективный код. А что бы получить такую же эффективность как в С++ надо попариться — реализовывать вручную функции работы со строками, эмулировать таблицы виртуальных функций и т.д.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Скорость работы с использованием классов и без
От: MShura  
Дата: 14.08.06 09:12
Оценка:
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++

string Func( string person, string phone, string address )
{
  string ret = person + " : " + phone + " : " + address;
  ...
  return ret;
}


Написать на C то, что делает здесь компилятор C++ не сможет ни один человек в здравом уме.
Re[7]: Скорость работы с использованием классов и без
От: Cyberax Марс  
Дата: 14.08.06 09:38
Оценка:
MShura wrote:
> Написать на C то, что делает здесь компилятор C++ не сможет ни один
> человек в здравом уме.
А вот с const_string'ом все будет замечательно, потому как expression
templates.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Скорость работы с использованием классов и без
От: 0xDEADBEEF Ниоткуда  
Дата: 14.08.06 22:40
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.08.06 04:52
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 09:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, remark, Вы писали:


R>>Согласен, возможно, я зря сказал за всех.

R>>Активное пользование такой структурой в приложении похвально. Но.
R>>1. Полностью это не изменит ситуацию, т.к. посмотрите на WinAPI и на другие c-style библиотеки. Какие-нибудь из них принимают такие структуры? Правильно, Нет! Значит опять возвращаемся к strlen().
S>Неправильно. Большинство функций WinAPI принимают и возвращают длину вместе со строкой. Так что вместо strlen нужно просто аккуратно использовать эту информацию.

Могу с тем же успехом сказать обратное
Согласен, что функции, которые работают с большими объёмами данных скорее всего принимают размер (WSASend, MultiByteToWideChar).
Но большинство других функций не принимают размер.
Тут стоит подумать над самим подходом — типа пока не припрёт, размер передавать не будем, пусть память постоянно зря перелопачивается. Тем более, что у меня функция уже принимает 8 параметров, если я ещё и размеры строк буду принимать, то получится 13, лучше уж я сам длину посчитаю. В С++ другой подход — вместе со строкой всегда передаём размер.


R>>

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 09:43
Оценка: +1
Здравствуйте, 0xDEADBEEF, Вы писали:

K>>Понятно, что использование таблиц виртуальных функций влияет на производительность программ, но как сильно?

DEA>Косвенный вызов против прямого. Проверить как это бьет по производительности — тривиально. Тем более, матерому сишнику. Надо только учесть, что виртуальных методов не так уж и много. Точнее, должно быть немного. Но бывает наоборот и тогда они превращаются в геморрой. Пример — реализация (требуемая стандартом) библиотеки потоков ввода-вывода (iostream). Часто народ ругается что большая она и тормознутая, но почему-то никто не переписывает.

K>>Влияет ли на работу использование обособленых классов (т.е. без наследования, виртуальных функций и других прелестей ООП) просто как структур для инкапсуляции полей и методов?

DEA>Добавляется только "спрятанный" параметр в вызовах функций. А именно — указатель на класс — this.

В продолжение здесь
Автор: remark
Дата: 11.08.06

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

"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров?
А как бы такая же задача решалась на С?
В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this.
А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее?

Про виртуальные функции. С++ программист просто так их не вводит, С-программисту придётся что-то вручную наворачивать, что бы съэмулировать аналогичное поведение.
Самые очевидные:
1. Съэмулировать таблицу виртуальных функций. Не получаем никаких выгод, только необходимость всё делать ручками (применяется редко).
2. Повсеместно использовать Switch-On-Type (применяется часто). Проигрываем по скорости, проигрываем по памяти + приходится везде дублировать SOT + склонно к ошибкам...


Предлагаю вообще переформулировать вопрос следующим образом:
Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 11:57
Оценка: -1
R>"При вызове метода добавляется скрытый параметр this". По сравнению с чем? С функцией без параметров?
R>А как бы такая же задача решалась на С?
Точно также и решается.
Явный указатель на структуру данных.

R>В лучшем случае в функцию передавалась бы одна структура через указатель. Очевидно, что это решение тождественно по всем параметрам передаче this.

R>А зачастую (С-библиотеки мы знаем — WinAPI, Oci и т.д.) в функцию передаётся 5-15 скалярных значений. А вот тут ещё большой вопрос, что будет быстрее?
Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование.
Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL.
ЭТО НЕВОЗМОЖНО.


R>Предлагаю вообще переформулировать вопрос следующим образом:

R>Имеет ли С хоть какие-то шансы приблизиться к С++ по производительности при разумных дополнительных затратах времени и сил С-программистом?

При правильном использовании C++ его производительность будет приближаться к C.
Подумайте например какой ценой можно завести C++ объект в любом месте функции.
Re[4]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 12:12
Оценка:
Здравствуйте, MShura, Вы писали:


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++ объект в любом месте функции.


Разместить его на стеке?



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Переформулируем вопрос
От: 0xDEADBEEF Ниоткуда  
Дата: 15.08.06 12:17
Оценка: +1
Здравствуйте, 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.
Re[4]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 12:42
Оценка:
MShura wrote:
> Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли
> пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с
> разными STL.
> ЭТО НЕВОЗМОЖНО.
Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[4]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 12:44
Оценка:
0xDEADBEEF wrote:
> Если хочешь иллюстрацию — посмотри на две реализации XML-парсеров. Обе —
> весьма "взрослые". Обе — решают одну и ту же проблему. Но, одна на C
> (libxml) а вторая — на C++ (xerces/xalan).
libxml — это как раз хороший пример объектно-ориентированного
программирования.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[5]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 12:57
Оценка:
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> Разместить его на стеке?

Обычно это дополнительная (неуправляеммая вами) переменная, которая используется для выяснения вызывался конструктор или нет.
Re[5]: Переформулируем вопрос
От: 0xDEADBEEF Ниоткуда  
Дата: 15.08.06 12:57
Оценка:
Здравствуйте, 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.
Re[6]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 13:11
Оценка:
0xDEADBEEF wrote:
> C>libxml — это как раз хороший пример объектно-ориентированного
> программирования.
> ...тогда примером какого программирования служит xerces? Тоже
> обьектно-ориентированного?
Да. Стандарт DOM XML — это, фактически, хрестоматийный пример ООП.

> Если да, то не находишь ли ты, подходы к обьектной ориентации у C и C++

> несколько различны?
То есть "подходы"? Они одинаковы, просто в С++ паттерны ООП
(наследование и виртуальность) вмонтированы в язык, а в С их нужно
делать самому.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[5]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 13:15
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>MShura wrote:

>> Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли
>> пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с
>> разными STL.
>> ЭТО НЕВОЗМОЖНО.
C>Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA.

Покажите мне std::string в COM.
Re[6]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 13:19
Оценка:
MShura wrote:
>> > Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли
>> > пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с
>> > разными STL.
>> > ЭТО НЕВОЗМОЖНО.
> C>Да без проблем. Смотри по ключевым словам: COM, XPCOM, CORBA.
> Покажите мне std::string в COM.
А зачем std::string? Есть comet::bstr_t, которая совместима с
std::string по API.

А еще есть http://www.zeroc.com/icee/cpp.html — там как раз std::string
в API.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[7]: Переформулируем вопрос
От: 0xDEADBEEF Ниоткуда  
Дата: 15.08.06 13:33
Оценка:
Здравствуйте, 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.
Re[7]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 13:40
Оценка:
Здравствуйте, 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?
Re[6]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 15.08.06 13:42
Оценка:
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
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 13:50
Оценка:
>> R> Разместить его на стеке?
>> Обычно это дополнительная (неуправляеммая вами) переменная, которая
>> используется для выяснения вызывался конструктор или нет.
_>Ты о чём? Зачем это выяснять? Вызов конструктора (если он есть!) происходит в том месте, где поставлена переменная. Т.е.
А если возврат из функции произошел раньше вызова конструктора?
Память для локальных переменных обычно выделяется при входе в функцию, т.е. даже для того, объекта который будет проинициалирован позже память уже выделена.
При раскрутке стека необходимо знать был ли проинициализорован объект с нетривиальным деструктором.
Re[8]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 14:04
Оценка:
MShura wrote:
> А если возврат из функции произошел раньше вызова конструктора?
Ну ты сам сказал — вызова конструктора не будет.

> При раскрутке стека необходимо знать был ли проинициализорован объект с

> нетривиальным деструктором.
Не обязательно. В случае табличных исключений — мы знаем какие
конструкторы уже отработали в данный момент.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[8]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 14:05
Оценка:
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.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[9]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:10
Оценка:
C>В разных версиях С++ — без проблем. Для VB/Delphi у них интерфейса нет.

Хорошо я еще раз процитирую своё предложение, с которым возникло несогласие

Основное преимущество библиотек написанных на C (вернее с C интерфейсом) — их использование.
Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с разными STL.
ЭТО НЕВОЗМОЖНО.


C>Если нужен совсем глобальный интерфейс — то еще раз смотри COM.

Опять же если этот интерфейс можно использовать в VB/Deplhi, то это не может быть C++ инерфейсом.
Re[9]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:18
Оценка:
>> А если возврат из функции произошел раньше вызова конструктора?
C>Ну ты сам сказал — вызова конструктора не будет.
С элементарным случаем согласились

>> При раскрутке стека необходимо знать был ли проинициализорован объект с

>> нетривиальным деструктором.
C>Не обязательно. В случае табличных исключений — мы знаем какие
C>конструкторы уже отработали в данный момент.
Пусть рассматириваемая функция вызвала другую, в которой произошло исключение. В нашей функции мы ислючение не ловим, а кто-то сверху его поймал. Вызывают раскрутку стека для каждой вызванной функции.
Во время раскрутки стека вызывается специальная функция, которая была создана компилятором для этих целей.
Вот перед нами фрейм с локальнами объектами. Кто-то проинициализорован, кто-то нет. Для кого вызывать деструкторы?
Re[10]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 14:20
Оценка:
MShura wrote:
> Основное преимущество библиотек написанных на C (вернее с C интерфейсом)
> — их использование.
> Попробуйте написать на C++ библиотеку аналог WinAPI, чтобы ей могли
> пользоваться из VB, Дельфи, а также из разных версий компилятора C++ с
> разными STL.
> ЭТО НЕВОЗМОЖНО.
Это утверждение неверно.
Во-первых, никто не мешает на С++ писать библиотеки с С-шным интерфейсом
(смотри, например, ODE — http://www.ode.org).
Во-вторых, можно использовать подход как в COM. То есть с интерфейсами+
QueryInterface и набором поддерживающих объектов (строки, массивы).

> C>Если нужен совсем глобальный интерфейс — то еще раз смотри COM.

> Опять же если этот интерфейс можно использовать в VB/Deplhi, то это не
> может быть C++ инерфейсом.
А если библитека на С используется из Pascal, то это уже не C-интерфейс?
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[10]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 14:27
Оценка:
MShura wrote:
> C>Не обязательно. В случае табличных исключений — мы знаем какие
> C>конструкторы уже отработали в данный момент.
> Пусть рассматириваемая функция вызвала другую, в которой произошло
> исключение. В нашей функции мы ислючение не ловим, а кто-то сверху его
> поймал. Вызывают раскрутку стека для каждой вызванной функции.
> Во время раскрутки стека вызывается специальная функция, которая была
> создана компилятором для этих целей.
> Вот перед нами фрейм с локальнами объектами. Кто-то проинициализорован,
> кто-то нет. Для кого вызывать деструкторы?
Компилятор при генерации строить специальные таблицы, по котором для
каждого положения указателя инструкций можно определить какие
деструкторы надо вызвать для размотки функции.

То есть для каждой функции имеем таблицу с записями вида "EIP —
destructor", упорядоченную по росту EIP. Соответственно, при размотке
стека по достижении начала функции мы смотрим в стек адрес возврата в
вызывающую функцию. По этому адресу берем таблицу размотки для функции и
разматываем те конструкторы, которые уже выполнились (для которых EIP
меньше адреса возврата).

В итоге имеем нулевой оверхед по скорости в случае нормальной работы, но
некоторый оверхед по объему исполняемого файла (так как таблицы нужно
хранить).

Кстати, в чистом С такое повторить не получится (точнее с ооооочень
большими трудозатратами).
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[11]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:34
Оценка:
C>Кстати, в чистом С такое повторить не получится (точнее с ооооочень
C>большими трудозатратами).

В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.
Re[12]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 14:37
Оценка:
Здравствуйте, MShura, Вы писали:


C>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень

C>>большими трудозатратами).

MS>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


Инициализируются в смысле под них выделяется хранилище (память)?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[12]: Переформулируем вопрос
От: Курилка Россия http://kirya.narod.ru/
Дата: 15.08.06 14:39
Оценка:
Здравствуйте, MShura, Вы писали:


C>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень

C>>большими трудозатратами).

MS>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


OutOfMemory очено ожиданный возврат?
Re[11]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:47
Оценка:
>> Основное преимущество библиотек написанных на 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 интерфейса именно в том, что им можно пользоваться из любого другого языка.
Re[13]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:50
Оценка:
C>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень
C>>>большими трудозатратами).

MS>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


К>OutOfMemory очено ожиданный возврат?

Как может возникнуть OutOfMemory при инициализации локальных переменных константными значениями?
Re[13]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 14:52
Оценка:
C>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень
C>>>большими трудозатратами).

MS>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


R>Инициализируются в смысле под них выделяется хранилище (память)?

Под локальные переменные память выделяет пролог функции.
Сами локальные переменные инициализируется уникальным константным значением (например NULL)
Re[14]: Переформулируем вопрос
От: Курилка Россия http://kirya.narod.ru/
Дата: 15.08.06 14:57
Оценка:
Здравствуйте, MShura, Вы писали:


C>>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень

C>>>>большими трудозатратами).

MS>>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


К>>OutOfMemory очено ожиданный возврат?

MS>Как может возникнуть OutOfMemory при инициализации локальных переменных константными значениями?

локальная переменная, скажем массив целых на 100000 байт, функция рекурсивная, как кончится память догадаешься?

Или у тебя своя терминология и локальная переменная только на стеке? но, надеюсь, ты в курсе, что стек вещь не бесконечная?
Re[14]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 15:00
Оценка:
Здравствуйте, MShura, Вы писали:

C>>>>Кстати, в чистом С такое повторить не получится (точнее с ооооочень

C>>>>большими трудозатратами).

MS>>>В C такой задачи не стоит, поскольку локальные "объекты" инициализируются в начале функции, до того, как могут возникнуть какие-либо исключения или другие неожиданные возвраты.


R>>Инициализируются в смысле под них выделяется хранилище (память)?

MS>Под локальные переменные память выделяет пролог функции.
MS>Сами локальные переменные инициализируется уникальным константным значением (например NULL)


Рассмотрим функцию на С:

void some_func()
{
  some_struct s;
  bool s_init = false;

  //...

  if (a)
  {
    //...
    init_some_struct(&s);
    s_init = true;
    //...
  }

  //...

  if (b)
  {
    //...
    if (s_init)
       uninit_some_struct(&s);
    return;
  }

  //...

  if (s_init)
     uninit_some_struct(&s);
}



Неужели тоже самое только (опять) вручную???
Или С-программисты делают как-то по-другому? В С-стиле программирования не силён, поэтому поправьте, если что.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[12]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 15:02
Оценка: +1
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);
};
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[13]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:16
Оценка:
>> C>Кстати, в чистом С такое повторить не получится (точнее с ооооочень
>> C>большими трудозатратами).
>> В C такой задачи не стоит, поскольку локальные "объекты"
>> инициализируются в начале функции, до того, как могут возникнуть
>> какие-либо исключения или другие неожиданные возвраты.
C>Да? И наверное именно поэтому один из самых распространенных паттернов в
C>С — это обработка ошибок через goto:
C>
C>void func()
C>{
C>    char *ptr1=NULL,*ptr2=NULL;
C>    ptr1=malloc(...);
C>    if (!ptr1) goto err_1;
C>    ptr2=malloc(...);
C>    if (!ptr2) goto err_2;

C>    err2: free(ptr2);
C>    err1: free(ptr1);
C>};
C>


Нормальный подход.
Если в условиях задачи разрешено использовать структурные исключения, то можно сделать через __try/__finally
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:18
Оценка:
R>Рассмотрим функцию на С:

R>
R>void some_func()
R>{
R>  some_struct s;
R>  bool s_init = false;

R>  //...

R>  if (a)
R>  {
R>    //...
R>    init_some_struct(&s);
R>    s_init = true;
R>    //...
R>  }

R>  //...

R>  if (b)
R>  {
R>    //...
R>    if (s_init)
R>       uninit_some_struct(&s);
R>    return;
R>  }

R>  //...

R>  if (s_init)
R>     uninit_some_struct(&s);
R>}
R>



R>Неужели тоже самое только (опять) вручную???

R>Или С-программисты делают как-то по-другому? В С-стиле программирования не силён, поэтому поправьте, если что.

Одна точка входа и одна точка выхода -> наиболее распространенный стиль программирования.
Примеры можно посмотреть в Linux или в Windows (DDK).
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:22
Оценка:
К>локальная переменная, скажем массив целых на 100000 байт, функция рекурсивная, как кончится память догадаешься?

К>Или у тебя своя терминология и локальная переменная только на стеке? но, надеюсь, ты в курсе, что стек вещь не бесконечная?


Смею вас уверить, что нехватка стека что в C++, что в C это смертельно, правда можно попытаться что-то сделать, но платформо зависимое.

P.S.
никто из знакомых мне программистов не выделит на стеке столько.
Re[14]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 15:27
Оценка:
MShura wrote:
> Нормальный подход.
> Если в условиях задачи разрешено использовать структурные исключения, то
> можно сделать через __try/__finally
Ну так это и есть ручная эмуляция исключений.

В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды возврата.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[8]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 15.08.06 15:28
Оценка:
MShura wrote:

>> > R> Разместить его на стеке?

>> > Обычно это дополнительная (неуправляеммая вами) переменная, которая
>> > используется для выяснения вызывался конструктор или нет.
> _>Ты о чём? Зачем это выяснять? Вызов конструктора (если он есть!)
> происходит в том месте, где поставлена переменная. Т.е.
> А если возврат из функции произошел раньше вызова конструктора?
Он не вызовется. А ты что думал?

> Память для локальных переменных обычно выделяется при входе в функцию,

> т.е. даже для того, объекта который будет проинициалирован позже память
> уже выделена.
Как в С, так и в С++. И что?

> При раскрутке стека необходимо знать был ли проинициализорован объект с

> нетривиальным деструктором.
Я привёл два листинга на С и С++ идентичные по коду.
А теперь мне покажи код на С, в котором будет нетривиальный деструктор (точнее его эмуляция) и кидание исключений
(точнее их эмуляция). Вот и будем их сравнивать, а пока фигню говоришь.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 15.08.06 15:29
Оценка:
Здравствуйте, MShura, Вы писали:

R>>Рассмотрим функцию на С:


MS>Одна точка входа и одна точка выхода -> наиболее распространенный стиль программирования.

MS>Примеры можно посмотреть в Linux или в Windows (DDK).

Ты лучше скажи по поводу s_init


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:38
Оценка: 1 (1)
>> Нормальный подход.
>> Если в условиях задачи разрешено использовать структурные исключения, то
>> можно сделать через __try/__finally
C>Ну так это и есть ручная эмуляция исключений.

C>В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды возврата.

Не вижу разницы если проект на C использует структурные исключения вместо кодов возврата.
C++ вызывает throw а в C RaiseException.
Если вы про new vs malloc, то элементарно сделать, чтобы malloc кидал структурное исключение.
Писанины больше, но и вся разница.
Кроме того, в структурных исключениях есть возможность продолжить выполнение с места исключения.
Очень удобно при формировании буферов неопределенной заранее длины.
Re[17]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:40
Оценка:
R>Ты лучше скажи по поводу s_init

Одна точка входа -> одна точка выхода:

void some_func()
{
  some_struct s;
  bool s_init = false;

  //...

  if (a)
  {
    //...
    init_some_struct(&s);
    s_init = true;
    //...
  }

  //...

  if (b)
  {
    //...
    goto Exit;
//    if (s_init)
//       uninit_some_struct(&s);
//    return;
  }

  //...

Exit:
  if (s_init)
     uninit_some_struct(&s);
}
Re[9]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 15:43
Оценка:
Уважаемый Cyberax понял о чем речь.

http://www.rsdn.ru/Forum/Message.aspx?mid=2059458&amp;only=1
Автор: Cyberax
Дата: 15.08.06
Re[10]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 15.08.06 15:59
Оценка:
MShura wrote:

> Уважаемый Cyberax понял о чем речь.

Он объяснил
Автор: Cyberax
Дата: 15.08.06
, что то, что делает С++ автоматически, тебе придётся делать
тоже самое вручную, к тому же только хуже, т.к. у тебя нет контроля стека, какой есть у С++ компилятора.
С++ лишь увеличивает размер бинарника под таблицы раскрутки, а в С будет <br />
дополнительный исполняемый код, что замедлит в итоге.
Автор: Cyberax
Дата: 15.08.06
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 16:45
Оценка:
>> Уважаемый Cyberax понял о чем речь.
_>Он объяснил
Автор: Cyberax
Дата: 15.08.06
, что то, что делает С++ автоматически, тебе придётся делать

_>тоже самое вручную, к тому же только хуже, т.к. у тебя нет контроля стека, какой есть у С++ компилятора.
_>С++ лишь увеличивает размер бинарника под таблицы раскрутки, а в С будет <br />
<span class='lineQuote level1'>_&gt;дополнительный исполняемый код, что замедлит в итоге.</span>
Автор: Cyberax
Дата: 15.08.06


Обычная задача оптимизации (как быстрее реализовать switch по таблице ссылок или прямым перебром — при небольшов варианте выбора прямой перебор быстрее).

Очень часто нет необходимости делать дополнительные проверки перед освобождением ресурсов.
Как показал сам Cyberax можно сделать несколько меток в конце функции (если ресурсы захватываются последовательно а именно так и происходит в большинстве функций), что убирает необходимость в дополнительных проверках.
Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle все равно проверяется перед вызовом CloseHandle.
(Хотя можно использовать full trusted обертку, но это редкость)
Если у Вас обертка над указателем, то написав delete компилятор вставляет код проверки на NULL, даже если вы как-то убедите его не делать этой проверки, то вызов функции OS для особождения памяти опять проверит указатель на NULL.

Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, что современные компиляторы умеют нивелировать косвенный вызов функции, что уж говорить об обычном ветвлении. К тому же есть подсказки компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.

Одним словом я бы не стал категорично заявлять, что код освобождения ресурсов в C больше оного в C++.

На этом заканчиваю на сегодня.
Re[12]: Переформулируем вопрос
От: MShura  
Дата: 15.08.06 16:47
Оценка:
MS>Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал, что современные компиляторы ...
Речь конечно о процессорах.
Re: Скорость работы с использованием классов и без
От: pavel_turbin  
Дата: 15.08.06 16:54
Оценка:
притормаживает большее количество временных объектов.

В C++ часто пишут


struct A
{
   string data;
};

vector<A> my_vector;

a1 = { "test" };
a2 = { "some other " };

my_vector.push_back( a1 ); 
my_vector.push_back( a2 );


при таком подходе возниканет несколько временных объектов и их копирование. Это замедляет. Особенно, если размер объекта большой или их много.
Re[12]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 15.08.06 17:04
Оценка:
MShura wrote:

> _>Он объяснил <http://rsdn.ru/forum/?mid=2059607&gt;
Автор: Cyberax
Дата: 15.08.06
, что то, что делает

> С++ автоматически, тебе придётся делать
> _>тоже самое вручную, к тому же только хуже, т.к. у тебя нет контроля
> стека, какой есть у С++ компилятора.
> _>С++ лишь увеличивает размер бинарника под таблицы раскрутки, а в С будет
>
> _>дополнительный исполняемый код, что замедлит в итоге.
> <http://rsdn.ru/forum/?mid=2059458&gt;
Автор: Cyberax
Дата: 15.08.06

>
> Обычная задача оптимизации (как быстрее реализовать 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]: Скорость работы с использованием классов и без
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.08.06 17:58
Оценка:
Здравствуйте, remark, Вы писали:
R>Но большинство других функций не принимают размер.
Как правило, это те функции, которые не выиграют от знания размера. У них алгоритм устроен так, что последовательное сканирование их вполне устраивает.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 19:44
Оценка:
MShura wrote:
> C>Ну так это и есть ручная эмуляция исключений.
> C>В данном случае С++ будет БЫСТРЕЕ, так как не надо проверять коды
> возврата.
> Не вижу разницы если проект на C использует структурные исключения
> вместо кодов возврата.
Для SEH нужно делать настройки каждого фрейма функции. Для исключений
С++ — необязательно.

> C++ вызывает throw а в C RaiseException.

> Если вы про new vs malloc, то элементарно сделать, чтобы malloc кидал
> структурное исключение.
> Писанины больше, но и вся разница.
> Кроме того, в структурных исключениях есть возможность продолжить
> выполнение с места исключения.
1. Где у нас SEH на Линуксе?
2. Как сделать SEH с zero-overhead по скорости?
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[12]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 15.08.06 19:49
Оценка: +2
MShura wrote:
> Как показал сам Cyberax можно сделать несколько меток в конце функции
> (если ресурсы захватываются последовательно а именно так и происходит в
> большинстве функций), что убирает необходимость в дополнительных проверках.
> Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle
> все равно проверяется перед вызовом CloseHandle.
Я вообще-то просил сказать чем это отличается от семантики
автоматических деструкторов (ответ: почти ничем).

> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал,

> что современные компиляторы умеют нивелировать *косвенный* вызов
> функции, что уж говорить об обычном ветвлении. К тому же есть подсказки
> компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.
Ну тогда какие вопросы к С++, который просто при инициализации объекта
устанавливает флаг?

> Одним словом я бы не стал категорично заявлять, что код освобождения

> ресурсов в C больше оного в C++.
Больше. В С++ с умными указателями тот же код:
scoped_array<char> arr1(new char[...]);
scoped_array<char> arr2(new char[...]);

Все! Причем нельзя забыть поставить cleanup в конце.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[13]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 09:38
Оценка:
>>
>> Обычная задача оптимизации (как быстрее реализовать 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++.
_>В лучшем случае такой же, но никак не меньше. За счёт чего может быть меньше?
Имелось в в виду не написанный, а сгенеренный код.
Re[13]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 10:11
Оценка: 4 (1)
>> Как показал сам Cyberax можно сделать несколько меток в конце функции
>> (если ресурсы захватываются последовательно а именно так и происходит в
>> большинстве функций), что убирает необходимость в дополнительных проверках.
>> Если у Вас обертка над открытым HANDLE, то в деструкторе значение handle
>> все равно проверяется перед вызовом CloseHandle.
C>Я вообще-то просил сказать чем это отличается от семантики
C>автоматических деструкторов (ответ: почти ничем).

>> Есть конечно экзотические ситуации, однако тот же Cyberax меня убеждал,

>> что современные компиляторы умеют нивелировать *косвенный* вызов
>> функции, что уж говорить об обычном ветвлении. К тому же есть подсказки
>> компилятору likely,unlikely (в gcc), которые еще нивелируют эту разницу.
C>Ну тогда какие вопросы к С++, который просто при инициализации объекта
C>устанавливает флаг?
Отвечаю на два вопроса.
В C можно никаких дополнительных переменных (неявных) не заводить.

>> Одним словом я бы не стал категорично заявлять, что код освобождения

>> ресурсов в C больше оного в C++.
C>Больше. В С++ с умными указателями тот же код:
C>
C>scoped_array<char> arr1(new char[...]);
C>scoped_array<char> arr2(new char[...]);
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;
}


Компилим: cl /c /O2 /EHs /GX /FAs tst.cpp
Версия компилятора 13.10.3052.

Можно смотреть сгенеренный asm, а можно воспользоваться помощью IDA.

Вот код Функции TestC

.text:00000000 ; int __cdecl TestC(void)
.text:00000000                 push    ebx
.text:00000001                 push    edi
.text:00000002                 push    64h ; 'd'
.text:00000004                 mov     ebx, 0FFFFFFF4h
.text:00000009                 call    _malloc
.text:0000000E                 mov     edi, eax
.text:00000010                 add     esp, 4
.text:00000013                 test    edi, edi
.text:00000015                 jz      short loc_44
.text:00000017                 push    esi
.text:00000018                 push    64h ; 'd'
.text:0000001A                 call    _malloc
.text:0000001F                 mov     esi, eax
.text:00000021                 add     esp, 4
.text:00000024                 test    esi, esi
.text:00000026                 jz      short loc_3A
.text:00000028                 push    esi
.text:00000029                 push    edi
.text:0000002A                 call    ?FuncC@@YAIPAD0@Z ; FuncC(char *,char *)
.text:0000002F                 push    esi
.text:00000030                 mov     ebx, eax
.text:00000032                 call    _free
.text:00000037                 add     esp, 0Ch
.text:0000003A 
.text:0000003A loc_3A:                                 ; CODE XREF: TestC(void)+26j
.text:0000003A                 push    edi
.text:0000003B                 call    _free
.text:00000040                 add     esp, 4
.text:00000043                 pop     esi
.text:00000044 
.text:00000044 loc_44:                                 ; CODE XREF: TestC(void)+15j
.text:00000044                 pop     edi
.text:00000045                 mov     eax, ebx
.text:00000047                 pop     ebx
.text:00000048                 retn
.text:00000048 ?TestC@@YAHXZ   endp
.text:00000048 
.text:00000048 _text           ends


Вот код функции TestCpp и её окружения
               Зачем здесь сгенерен конструктор?
.text:0000004A ; public: __thiscall std::auto_ptr<char>::auto_ptr<char>(char *)
.text:0000004A arg_0           = dword ptr  4
.text:0000004A 
.text:0000004A                 mov     eax, ecx
.text:0000004C                 mov     ecx, [esp+arg_0]
.text:00000050                 mov     [eax], ecx
.text:00000052                 retn    4
.text:00000052 ??0?$auto_ptr@D@std@@QAE@PAD@Z endp
.text:00000052 
.text:00000052 _text           ends
.text:00000052 
.text:00000056 
.text:00000056 ; public: __thiscall std::auto_ptr<char>::~auto_ptr<char>(void)
.text:00000056                 mov     eax, [ecx]
.text:00000058                 push    eax
.text:00000059                 call    ??3@YAXPAX@Z    ; operator delete(void *)
.text:0000005E                 pop     ecx
.text:0000005F                 retn
.text:0000005F ??1?$auto_ptr@D@std@@QAE@XZ endp
.text:0000005F 
.text:0000005F _text           ends
.text:0000005F 
.text:00000060 ; void __cdecl TestCpp(void)
.text:00000060 
.text:00000060 var_14          = dword ptr -14h
.text:00000060 var_10          = dword ptr -10h
.text:00000060 var_C           = dword ptr -0Ch
.text:00000060 var_4           = dword ptr -4
.text:00000060 
.text:00000060                 push    0FFFFFFFFh
.text:00000062                 push    offset __ehhandler$?TestCpp@@YAXXZ
.text:00000067                 mov     eax, dword ptr fs:__except_list
.text:0000006D                 push    eax
.text:0000006E                 mov     dword ptr fs:__except_list, esp
.text:00000075                 sub     esp, 8
.text:00000078                 push    64h ; 'd'
.text:0000007A                 call    ??_U@YAPAXI@Z
.text:0000007F                 mov     [esp+18h+var_10], eax
.text:00000083                 push    64h ; 'd'
.text:00000085                 mov     [esp+1Ch+var_4], 0            <--- Что это за переменная?
.text:0000008D                 call    ??_U@YAPAXI@Z
.text:00000092                 mov     [esp+1Ch+var_14], eax
.text:00000096                 lea     eax, [esp+1Ch+var_14]
.text:0000009A                 push    eax
.text:0000009B                 lea     ecx, [esp+20h+var_10]
.text:0000009F                 push    ecx
.text:000000A0                 mov     byte ptr [esp+24h+var_4], 1    <--- Что это за переменная?
.text:000000A5                 call    ?FuncCpp@@YAXAAV?$auto_ptr@D@std@@0@Z ; FuncCpp(std::auto_ptr<char> &,std::auto_ptr<char> &)
.text:000000AA                 mov     edx, [esp+24h+var_14]
.text:000000AE                 push    edx
.text:000000AF                 call    ??3@YAXPAX@Z    ; operator delete(void *)
.text:000000B4                 mov     eax, [esp+28h+var_10]
.text:000000B8                 push    eax
.text:000000B9                 call    ??3@YAXPAX@Z    ; operator delete(void *)
.text:000000BE                 mov     ecx, [esp+2Ch+var_C]
.text:000000C2                 mov     dword ptr fs:__except_list, ecx
.text:000000C9                 add     esp, 2Ch
.text:000000CC                 retn
.text:000000CC ?TestCpp@@YAXXZ endp
.text:000000CC 
.text:000000CC _text           ends
.text:000000CC 
.text$x:000000CE 
.text$x:000000CE $L48140         proc near               ; DATA XREF: .xdata$x:000000ECo
.text$x:000000CE                 lea     ecx, [ebp-10h]
.text$x:000000D1                 jmp     ??1?$auto_ptr@D@std@@QAE@XZ ; std::auto_ptr<char>::~auto_ptr<char>(void)
.text$x:000000D1 $L48140         endp
.text$x:000000D1 
.text$x:000000D6 
.text$x:000000D6 $L48141         proc near               ; DATA XREF: .xdata$x:000000F4o
.text$x:000000D6                 lea     ecx, [ebp-14h]
.text$x:000000D9                 jmp     ??1?$auto_ptr@D@std@@QAE@XZ ; std::auto_ptr<char>::~auto_ptr<char>(void)
.text$x:000000D9 $L48141         endp
.text$x:000000D9 
.text$x:000000DE 
.text$x:000000DE __ehhandler$?TestCpp@@YAXXZ proc near   ; DATA XREF: TestCpp(void)+2o
.text$x:000000DE                 mov     eax, offset $T48161
.text$x:000000E3                 jmp     ___CxxFrameHandler
.text$x:000000E3 __ehhandler$?TestCpp@@YAXXZ endp
.text$x:000000E3 
.text$x:000000E3 _text$x         ends
.text$x:000000E3 
.xdata$x:000000E8 ; ===========================================================================
.xdata$x:000000E8 
.xdata$x:000000E8 ; Segment type: Pure data
.xdata$x:000000E8 _xdata$x        segment dword public 'DATA' use32
.xdata$x:000000E8                 assume cs:_xdata$x
.xdata$x:000000E8                 ;org 0E8h
.xdata$x:000000E8 $T48164         dd 0FFFFFFFFh           ; DATA XREF: .xdata$x:00000100o
.xdata$x:000000EC                 dd offset $L48140
.xdata$x:000000F0                 dd 0
.xdata$x:000000F4                 dd offset $L48141
.xdata$x:000000F8 $T48161         dd 19930520h            ; DATA XREF: __ehhandler$?TestCpp@@YAXXZo
.xdata$x:000000FC                 dd 2
.xdata$x:00000100                 dd offset $T48164
.xdata$x:00000104                 dd 0
.xdata$x:00000108                 dd 0
.xdata$x:0000010C                 dd 0
.xdata$x:00000110                 dd 0
.xdata$x:00000110 _xdata$x        ends



Считаем:
Код функции TestC: 0x4A
Код Функции TestCpp: 0xCE-0x60 = 0x6E
auto_ptr<char>::~auto_ptr<char> : 0x60-0x56 = 0xA
два освободителя 0xDE-0xCE = 0x10
код раскрутки стека: 0xE3 — 0xDE = 5
таблицы: 0x110 — 0xE8 = 0x28

Итого 74 байта vs 181.
Плюс глубина использования стека 0x20 vs 0x2С
Re[14]: Переформулируем вопрос
От: FR  
Дата: 16.08.06 10:41
Оценка:
Здравствуйте, MShura, Вы писали:


MS>Конечно код написанный программистом на C++ будет меньше в текстовом виде, но больше в двоичном.


Фигня, скорость будет практически одинаковой.

MS>пример:


там у тебя ошибка в auto_ptr нельзя давать new []
Re[14]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 16.08.06 13:25
Оценка: 4 (1)
MShura wrote:

Лажа какая-то. Вот мой асм:
PUBLIC    ?TestC@@YAHXZ                    ; TestC
EXTRN    _free:NEAR
EXTRN    _malloc:NEAR
; Function compile flags: /Ogty
;    COMDAT ?TestC@@YAHXZ
_TEXT    SEGMENT
?TestC@@YAHXZ PROC NEAR                    ; TestC, COMDAT

; 30   : {

    push    esi
    push    edi

; 31   :   int err = -ENOMEM;
; 32   :   char* a, *b;
; 33   :
; 34   :   a = (char*)malloc( 100 );

    push    100                    ; 00000064H
    mov    esi, -12                ; fffffff4H
    call    _malloc
    mov    edi, eax
    add    esp, 4

; 35   :   if ( NULL == a )

    test    edi, edi
    je    SHORT $L10293

; 36   :     goto end1;
; 37   :
; 38   :   b = (char*)malloc( 100 );

    push    100                    ; 00000064H
    call    _malloc
    add    esp, 4

; 39   :   if ( NULL == b )

    test    eax, eax
    je    SHORT $end2$8985

; 40   :     goto end2;
; 41   :
; 42   :   err = FuncC( a, b );
; 43   :
; 44   :   free( b );

    push    eax
    xor    esi, esi
    call    _free
    add    esp, 4
$end2$8985:

; 45   : end2:
; 46   :   free( a );

    push    edi
    call    _free
    add    esp, 4
$L10293:
    pop    edi

; 47   : end1:
; 48   :   return err;

    mov    eax, esi
$end1$8981:
    pop    esi

; 49   : }

    ret    0
?TestC@@YAHXZ ENDP                    ; TestC


?TestCpp@@YAXXZ PROC NEAR                ; TestCpp, COMDAT

; 12   : {

    push    -1
    push    __ehhandler$?TestCpp@@YAXXZ
    mov    eax, DWORD PTR fs:__except_list
    push    eax
    mov    DWORD PTR fs:__except_list, esp
    push    ecx
    push    esi

; 13   :     std::auto_ptr<char> a ( new char [100] );

    push    100                    ; 00000064H
    call    ??_U@YAPAXI@Z                ; operator new[]
    mov    esi, eax
    mov    DWORD PTR _a$[esp+24], esi

; 14   :     std::auto_ptr<char> b ( new char [100] );

    push    100                    ; 00000064H
    mov    DWORD PTR __$EHRec$[esp+36], 0
    call    ??_U@YAPAXI@Z                ; operator new[]

; 15   :     FuncCpp( a, b );
; 16   : }

    push    eax
    call    ??3@YAXPAX@Z                ; operator delete
    push    esi
    call    ??3@YAXPAX@Z                ; operator delete
    mov    ecx, DWORD PTR __$EHRec$[esp+36]
    add    esp, 16                    ; 00000010H
    pop    esi
    mov    DWORD PTR fs:__except_list, ecx
    add    esp, 16                    ; 00000010H
    ret    0
_TEXT    ENDS
;    COMDAT text$x
text$x    SEGMENT
$L10399:
    lea    ecx, DWORD PTR _a$[ebp]
    jmp    ??1?$auto_ptr@D@std@@QAE@XZ        ; std::auto_ptr<char>::~auto_ptr<char>
__ehhandler$?TestCpp@@YAXXZ:
    mov    eax, OFFSET FLAT:$T10423
    jmp    ___CxxFrameHandler
text$x    ENDS
?TestCpp@@YAXXZ ENDP                    ; TestCpp

Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог
функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И 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
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 13:37
Оценка:
_>Лажа какая-то. Вот мой асм:
...
Этот листинг полностью повторяет то, что я привел.

_>Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог

_>функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И asm данной функции на
_>С++ получился вообще без условных переходов, в отличие от С. Дополнительный код будет выполнятся только при
_>возникновении исключений (а по замыслу это редкие ситуации в С++).

То что дополнительных переходов нет это конечно хорошо.
Чуть расширьте пример (анализ содержимого в буфферах) и количество дополнительных переходов нивелируется количеством необходимых переходов.

Можно конечно возразить, что пример надуман.
Тогда милости просим сюда:
http://rsdn.ru/Forum/Message.aspx?mid=1469428&amp;only=1
Автор: _Winnie
Дата: 02.11.05
Re[15]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 16.08.06 13:42
Оценка:
Здравствуйте, kan_izh, Вы писали:

_>Т.е. кода обработки ошибок НЕТ вообще! Т.е. С++ код в отсутсвие исключений даже ПРОЩЕ, чем С код. Есть пролог и эпилог

_>функции, которые не содежрат условных операторов и переходов (хотя за счёт увеличения стека). И asm данной функции на
_>С++ получился вообще без условных переходов, в отличие от С. Дополнительный код будет выполнятся только при
_>возникновении исключений (а по замыслу это редкие ситуации в С++).


Полностью поддерживаю, что код на С++ с исключениями быстрее аналогичного на С изрезаного кучей if-ов.
Если функция с одним if-ом, то С, конечно быстрее, но если взять более сложный/реальный пример с глубиной вызовов порядка 10, то С++ с исключенями делает С с if'ами.

Читаемость и поддерживаемость кода на С — это отдельный момент. Давайте представим, что в функцию на С, которую MShura привёл здесь
Автор: MShura
Дата: 16.08.06
, надо добавить выделение ещё нескольких ресурсов, причём часть из них выделяется не всегда, а при некотором условии. Уууух, У меня волосы дыбом встали
И для контраста представим это код на С++. Это уже само по себе огромный плюс в сторону С++, даже если при этом скорость бы была ниже (хотя она ещё и выше).



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[16]: Переформулируем вопрос
От: kan_izh Великобритания  
Дата: 16.08.06 13:54
Оценка: +1
MShura wrote:

> То что дополнительных переходов нет это конечно хорошо.

> Чуть расширьте пример (анализ содержимого в буфферах) и количество
> дополнительных переходов нивелируется количеством необходимых переходов.
>
> Можно конечно возразить, что пример надуман.
> Тогда милости просим сюда:
> <http://rsdn.ru/Forum/Message.aspx?mid=1469428&amp;only=1&gt;
Автор: _Winnie
Дата: 02.11.05

при простом включении опции "enable exception handling"

Считай, что вставились проверки в каждый "new". А они были до? Надо сравнивать "простое включение" с расстановкой по
всему коду явных проверок каждого malloc и прочих функций, могущих кинуть исключение... А то получилось сравнение кода вида:
char *buf = malloc(100);
buf[1]=5;

с кодом
char *buf = malloc(100);
if(buf == NULL) goto removeAllResourcesAndFindAppropriateCatchBlock;
buf[1]=5;
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[14]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 16.08.06 14:08
Оценка: 1 (1)
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


Вот результат:
    .type    TestC, @function
TestC:
.LFB12:
    movq    %rbp, -16(%rsp)
.LCFI0:
    movq    %r12, -8(%rsp)
.LCFI1:
    movl    $100, %edi
    movq    %rbx, -24(%rsp)
.LCFI2:
    subq    $24, %rsp
.LCFI3:
    movl    $-12, %r12d
    call    malloc@PLT
    testq    %rax, %rax
    movq    %rax, %rbp
    je    .L4
    movl    $100, %edi
    call    malloc@PLT
    testq    %rax, %rax
    movq    %rax, %rbx
    je    .L7
    movq    %rbp, %rdi
    movq    %rax, %rsi
    call    FuncC@PLT
    movq    %rbx, %rdi
    movl    %eax, %r12d
    call    free@PLT
.L7:
    movq    %rbp, %rdi
    call    free@PLT
.L4:
    movl    %r12d, %eax
    movq    (%rsp), %rbx
    movq    8(%rsp), %rbp
    movq    16(%rsp), %r12
    addq    $24, %rsp
    ret


А теперь для С++ (gcc -O2 -S -fPIC test.cpp):
.globl _Z7TestCppv
    .type    _Z7TestCppv, @function
_Z7TestCppv:
.LFB447:
    pushq    %rbx
.LCFI0:
    movl    $100, %edi
    subq    $32, %rsp
.LCFI1:
.LEHB0:
    call    _Znam@PLT
.LEHE0:
    movl    $100, %edi
    movq    %rax, 16(%rsp)
.LEHB1:
    call    _Znam@PLT
.LEHE1:
    movq    %rax, (%rsp)
    movq    %rsp, %rsi
    leaq    16(%rsp), %rdi
.LEHB2:
    call    _Z7FuncCppRSt8auto_ptrIcES1_@PLT
.LEHE2:
    movq    (%rsp), %rdi
    call    _ZdlPv@PLT
    movq    16(%rsp), %rdi
    call    _ZdlPv@PLT
    addq    $32, %rsp
    popq    %rbx
    ret


Для размотки стека генерируется ОТДЕЛЬНЫЙ код, который при обычном
исполнении никак не влияет на результат:
.L7:
    movq    %rax, %rbx
.L4:
    movq    16(%rsp), %rdi
    call    _ZdlPv@PLT
    movq    %rbx, %rdi
.LEHB3:
    call    _Unwind_Resume@PLT
.LEHE3:
.L6:
.L3:
    movq    (%rsp), %rdi
    movq    %rax, %rbx
    call    _ZdlPv@PLT
    jmp    .L4
.LFE447:
    .size    _Z7TestCppv, .-_Z7TestCppv
.globl __gxx_personality_v0
    .section    .gcc_except_table,"a",@progbits
.LLSDA447:
    .byte    0xff
    .byte    0xff
    .byte    0x1
    .uleb128 .LLSDACSE447-.LLSDACSB447
.LLSDACSB447:
    .uleb128 .LEHB0-.LFB447
    .uleb128 .LEHE0-.LEHB0
    .uleb128 0x0
    .uleb128 0x0
    .uleb128 .LEHB1-.LFB447
    .uleb128 .LEHE1-.LEHB1
    .uleb128 .L7-.LFB447
    .uleb128 0x0
    .uleb128 .LEHB2-.LFB447
    .uleb128 .LEHE2-.LEHB2
    .uleb128 .L6-.LFB447
    .uleb128 0x0
    .uleb128 .LEHB3-.LFB447
    .uleb128 .LEHE3-.LEHB3
    .uleb128 0x0
    .uleb128 0x0


Итого имеем: код на С++ занимает меньше места в исходном виде и
выполнятется быстрее Сшного кода.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 14:56
Оценка:
Здравствуйте, 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
Re[16]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 16.08.06 18:20
Оценка:
MShura wrote:
> C>А теперь считаю я:
> ...
> C>Итого имеем: код на С++ занимает меньше места в исходном виде и
> C>выполнятется быстрее Сшного кода.
> Хороший ответ. Однако вы не подсчитали размеры.
> Я сделаю это за Вас (gcc версии 4.0.2):
> TestC: 0x60
> TestCpp: 0x4B
> Обвязка TestCpp: 0xAC
Ну так я говорил, что ускорение покупается ценой увеличения размера
бинариков. Однако, линкер распологает секции с информациях о EH в
отдельную область exe-шника, так что при нормальной работе это не влияет
на cache locality.

> Усложним задачу?

Для С++:
         .type   _Z7TestCppv, @function
_Z7TestCppv:
.LFB447:
         movq    %rbx, -24(%rsp)
.LCFI0:
         movq    %rbp, -16(%rsp)
.LCFI1:
         movl    $100, %edi
         movq    %r12, -8(%rsp)
.LCFI2:
         subq    $56, %rsp
.LCFI3:
.LEHB0:
         call    _Znam@PLT
.LEHE0:
         movl    $100, %edi
         movq    %rax, 16(%rsp)
.LEHB1:
         call    _Znam@PLT
.LEHE1:
         leaq    16(%rsp), %rbp
         movq    %rax, (%rsp)
         xorl    %edx, %edx
         movq    %rsp, %rsi
         movq    %rbp, %rdi
.LEHB2:
         call    _Z7FuncCppRSt8auto_ptrIcES1_i@PLT
.LEHE2:
.L2:
         movq    (%rsp), %rdi
         call    _ZdlPv@PLT
         movq    16(%rsp), %rdi
         call    _ZdlPv@PLT
         movq    32(%rsp), %rbx
         movq    40(%rsp), %rbp
         movq    48(%rsp), %r12
         addq    $56, %rsp
         ret


И код EH:
.L13:
         movq    %rax, %r12
.L7:
         movq    16(%rsp), %rdi
         call    _ZdlPv@PLT
         movq    %r12, %rdi
.LEHB3:
         call    _Unwind_Resume@PLT
.LEHE3:
.L11:
.L3:
         movq    %rax, %rdi
         call    __cxa_begin_catch@PLT
         movl    $1, %edx
         movq    %rsp, %rsi
         movq    %rbp, %rdi
.LEHB4:
         call    _Z7FuncCppRSt8auto_ptrIcES1_i@PLT
.LEHE4:
.LEHB5:
         call    __cxa_end_catch@PLT
.LEHE5:
         jmp     .L2
.L10:
.L5:
         movq    %rax, %r12
         .p2align 4,,6
         call    __cxa_end_catch@PLT
.L6:
         movq    (%rsp), %rdi
         call    _ZdlPv@PLT
         jmp     .L7
.L12:
         movq    %rax, %r12
         .p2align 4,,4
         jmp     .L6

Опять же, в нормальном ходе исполнения никаких накладных расходов на
исключения.

Теперь для С:
         .type   TestC, @function
TestC:
.LFB12:
         movq    %rbp, -16(%rsp)
.LCFI0:
         movq    %r12, -8(%rsp)
.LCFI1:
         movl    $100, %edi
         movq    %rbx, -24(%rsp)
.LCFI2:
         subq    $24, %rsp
.LCFI3:
         movl    $-12, %r12d
         call    malloc@PLT
         testq   %rax, %rax
         movq    %rax, %rbp
         je      .L4
         movl    $100, %edi
         call    malloc@PLT
         testq   %rax, %rax
         movq    %rax, %rbx
         je      .L7
         xorl    %edx, %edx
         movq    %rax, %rsi
         movq    %rbp, %rdi
         call    FuncC@PLT
         xorl    %r12d, %r12d
         testl   %eax, %eax
         jne     .L13
.L10:
         movq    %rbx, %rdi
         call    free@PLT
.L7:
         movq    %rbp, %rdi
         call    free@PLT
.L4:
         movl    %r12d, %eax
         movq    (%rsp), %rbx
         movq    8(%rsp), %rbp
         movq    16(%rsp), %r12
         addq    $24, %rsp
         ret
         .p2align 4,,7

А тут у нас появились ветвления. Причем предиктор вполне может в первое
прохождение кода их предсказать неправильно.

> Подсчитайте теперь.

> При тех-же условиях у меня получилось
> 0x80 vs 0xAC + 0x9C
Ну да, получается больший размер.
У меня для С++:
.text = b5
.gcc_except_table = 28
Имеем DD (221)

Для С:
.text = 8c (140)
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[15]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 18:43
Оценка:
C>Итого имеем: код на С++ занимает меньше места в исходном виде и
C>выполнятется быстрее Сшного кода.

Количество инструкций и ветвлений в C коде будет не больше количества инструкций и ветвлений в C++.
Да код только функции TestC больше кода TestCpp (в gcc), но уверены ли вы, что в исполняемом коде обвязка TestCpp будет помещена в другую страницу?
Если обвязка TestCpp будет располагаться рядом с самой функцией то боюсь что размер функция + обвязка имеет значение (не в пользу С++)
Re[16]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 16.08.06 19:26
Оценка:
MShura wrote:
> C>Итого имеем: код на С++ занимает меньше места в исходном виде и
> C>выполнятется быстрее Сшного кода.
> Количество инструкций и ветвлений в C коде будет не больше количества
> инструкций и ветвлений в C++.
Будет. И есть. Посчитай количество ветвлений в коде на С++ (подсказываю:
ноль).

Табличный EH позволяет исполнять код с исключениями без всяких накладных
расходов по скорости.

> Да код только функции TestC больше кода TestCpp (в gcc), но уверены ли

> вы, что в исполняемом коде обвязка TestCpp будет помещена в другую страницу?
Уверен. Линкер и компилиятор не дураки писали и про локальность кэша знают.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[17]: Переформулируем вопрос
От: MShura  
Дата: 16.08.06 20:13
Оценка:
>> 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>Уверен. Линкер и компилиятор не дураки писали и про локальность кэша знают.

Для этого надо бы посмотреть карту готового (желательно немаленького) бинарника и убедиться что все обработчики лежат рядышком и в далеке от основного кода.
Re[18]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 17.08.06 04:23
Оценка:
Здравствуйте, 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'ы, вместе с производительностью значительно снижается читаемость и понятность кода.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[17]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 17.08.06 04:39
Оценка:
Здравствуйте, 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'ов (при достижении некоторой пороговой, не очень большой, вложенности вызовов функций и их количества. а количество функций и вложенность сейчас обычно велика и только растёт со временем развития системы).


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[16]: Переформулируем вопрос
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.08.06 06:34
Оценка: +1
Здравствуйте, MShura, Вы писали:

MS>Усложним задачу?

Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Переформулируем вопрос
От: remark Россия http://www.1024cores.net/
Дата: 17.08.06 07:02
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, MShura, Вы писали:


MS>>Усложним задачу?

S>Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.

Да, я предлагаю усложить так, что будем выделять не массив char'ов, а массив объектов, у которых есть нетривиальный конструктор и деструктор. Соответственно в С выделяем массив структур и надо вызывать функцию init()/deinit() для каждой структуры


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[18]: Переформулируем вопрос
От: MShura  
Дата: 17.08.06 07:23
Оценка:
R>Моё мнение по этому поводу такое.
R>Для настольных и тем более для серверных систем размер диска и ОП перестали быть узким местом. Касательно ОП я имею в виду те изменения размера, о которых идёт речь. А вот ЦП зачастую становится узким местом, особенно для серверных систем.
R>Поэтому я бы сходу променял несколько мегабайт бинарника на увеличившуюся производительность. Особенно, если то, что написал Cyberax по поводу cache locality, действительно имеет место.

Боюсь вас огорчить по поводу cache locality.
Я не знаю как у Cyberax, но в коде, который сгенерил мой gcc 4.0.2 обработчик лежит в том же сегменте, что и основная функция.
Линкер ну никак не сможет его поместить подальше от основного кода.
Re[17]: Переформулируем вопрос
От: MShura  
Дата: 17.08.06 07:24
Оценка:
MS>>Усложним задачу?
S>Я боюсь, что усложняя задачу, ты будешь все сильнее и сильнее встревать. Потому, что С++ компилер делает автоматически все то, что тебе придется делать руками.

С увеличением количества объектов C++ будет отставать всё больше и больше.
Re[12]: Скорость работы с использованием классов и без
От: gear nuke  
Дата: 26.08.06 06:53
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: FR  
Дата: 26.08.06 07:22
Оценка:
Здравствуйте, gear nuke, Вы писали:

GN>Здравствуйте, Cyberax, Вы писали:


C>>В новых процессорах есть предсказатель косвенных переходов. Погугли по словам "indirect branch prediction".


GN>Для вызова через VTable необходимо 2 косвенных чтения (1й — читаем адрес таблицы, и только 2й — вызов функции).


чтения да два, но переход то один.
Re[14]: Скорость работы с использованием классов и без
От: gear nuke  
Дата: 26.08.06 07:40
Оценка:
Здравствуйте, 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]: Скорость работы с использованием классов и без
От: FR  
Дата: 26.08.06 07:53
Оценка: +1
Здравствуйте, gear nuke, Вы писали:

GN>Здравствуйте, FR, Вы писали:


FR>>чтения да два, но переход то один.


GN>В принципе, да... как я понимаю, предсказатель говорит: команда косвенного перехода, расположенная по такому-то адресу, перейдёт туда-то. То есть можно тупо откинуть анализ поинтера на VTable.


Угу, нужно только помнить с какой точки и куда ходили.

GN>А потом вспоминаем пример полиморфизма из книжки Sprite.Draw(). И потомков у этого класса — 68. Все они обрабатываются в цикле, при рендеринге сцены в аркадной игрушке... А конвеер у последних процев очень уж свехдлинный и его сброс далеко не бесплатен


Плохой пример на фоне Sprite.Draw() затраты и на вызов виртуальной функции (и не только виртуальной, но и даже функции из скрипта) и на сброс конвеера равны нулю
Re[16]: Скорость работы с использованием классов и без
От: gear nuke  
Дата: 26.08.06 08:21
Оценка: :)
Здравствуйте, 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
Re[14]: Переформулируем вопрос
От: gear nuke  
Дата: 26.08.06 09:03
Оценка:
Здравствуйте, MShura, Вы писали:

[]

MS>Вот код функции TestCpp и её окружения

MS>
MS>               Зачем здесь сгенерен конструктор?
MS>.text:0000004A ; public: __thiscall std::auto_ptr<char>::auto_ptr<char>(char *)
MS>.text:0000004A arg_0           = dword ptr  4
MS>.text:0000004A 
MS>.text:0000004A                 mov     eax, ecx
MS>.text:0000004C                 mov     ecx, [esp+arg_0]
MS>.text:00000050                 mov     [eax], ecx
MS>.text:00000052                 retn    4
MS>.text:00000052 ??0?$auto_ptr@D@std@@QAE@PAD@Z endp
[]
MS>


Есть такие проблемы у компилятора. Решаются (иногда) при помощи /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
Re[17]: Переформулируем вопрос
От: gear nuke  
Дата: 26.08.06 09:03
Оценка:
Здравствуйте, 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
Re[17]: Переформулируем вопрос
От: gear nuke  
Дата: 26.08.06 09:03
Оценка:
Здравствуйте, 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
Re[18]: Переформулируем вопрос
От: Cyberax Марс  
Дата: 26.08.06 12:20
Оценка:
gear nuke wrote:
> C>Линкер и компилиятор не дураки писали и про локальность кэша знают.
> Задача решаема только для JIT. У разных CPU разные характиристики кеша.
Ну почему же, можно поступить и как Linux Gentoo — компилировать все на
машине пользователя с оптимизациями под точную модель процессора.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[19]: Переформулируем вопрос
От: gear nuke  
Дата: 26.08.06 12:24
Оценка:
Здравствуйте, 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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.