C++ 3d.Комментарии


Эффективность и структура - часть 2


А что же inline? Давайте внесем очевидные изменения: struct A { A() { Var++; }

~A() { Var++; }

};

void f1() { A a; }

void f2() { Var++; Var++;

}

Теперь разницы во времени работы f1() и f2() не быть должно. К несчастью, на большинстве компиляторов она все же присутствует.

Что же происходит? Наблюдаемый нами эффект называется abstraction penalty, т.е. обратная сторона абстракции или налагаемое на нас некачественными компиляторами наказание за использование (объектно-ориентированных) абстракций.

Давайте посмотрим как abstraction penalty проявляется в нашем случае.

Что же из себя представляет void f1() { A a; }

эквивалентное void f1() // псевдокод { A::A(); A::~A(); }

И чем оно отличается от простого вызова двух функций: void f2() { ACon(); ADes(); }

В данном случае -- ничем! Но, давайте рассмотрим похожий пример: void f1() { A a; f(); }

void f2() { ACon(); f(); ADes(); }

Как вы думаете, эквивалентны ли данные функции? Правильный ответ -- нет, т.к. f1() представляет собой void f1() // псевдокод { A::A();

try { f(); } catch (...) { A::~A(); throw; }

A::~A(); }

Т.е. если конструктор успешно завершил свою работу, то языком гарантируется, что обязательно будет вызван деструктор. Т.е. там, где создаются некоторые объекты, компилятор специально вставляет блоки обработки исключений для гарантии вызова соответствующих деструкторов. А накладные расходы в оригинальной f1() чаще всего будут вызваны присутствием ненужных в данном случае блоков обработки исключений (фактически, присутствием "утяжеленных" прологов/эпилогов): void f1() // псевдокод { A::A();

try { // пусто } catch (...) { A::~A(); throw; }

A::~A(); }

Дело в том, что компилятор обязан корректно обрабатывать все возможные случаи, поэтому для упрощения компилятора его разработчики часто не принимают во внимание "частные случаи", в которых можно не генерировать ненужный код. Увы, подобного рода упрощения компилятора очень плохо сказываются на производительности интенсивно использующего средства абстракции и inline функции кода. Хорошим примером подобного рода кода является STL, чье использование, при наличии плохого оптимизатора, вызывает чрезмерные накладные расходы.

Поэкспериментируйте со своим компилятором для определения его abstraction penalty -- гарантированно пригодится при оптимизации "узких мест".




- Начало -  - Назад -  - Вперед -



Книжный магазин