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




Виртуальные функции - часть 2


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

Судя по всему, от этих расходов можно отказаться, реализовав вызов виртуальной функции специальным образом, а именно: каждый раз вычисляя положение vptr относительно this и пересчитывая индекс вызываемой виртуальной функции в vtbl. Однако это спровоцирует существенные расходы времени выполнения, что неприемлемо.

И раз уж так много слов было сказано про эффективность, давайте реально измерим относительную стоимость вызова виртуальной функции. #include <stdio.h> #include <stdlib.h> #include <time.h>

struct B { void f(); virtual void vf(); };

struct D : B { void vf(); // замещаем B::vf };

void f1(B* ptr) { ptr->f(); }

void f2(B* ptr) { ptr->vf(); }

long Var, Count;

void B::f() { Var++; } void B::vf() { }

void D::vf() { Var++; }

int main(int argc,char** argv) { if (argc>1) Count=atol(argv[1]);

clock_t c1,c2;

D d; { c1=clock();

for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f1(&d);

c2=clock(); printf("f1(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } { c1=clock();

for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f2(&d);

c2=clock(); printf("f2(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } }

В зависимости от компилятора и платформы, накладные расходы на вызов виртуальной функции составили от 10% до 2.5 раз. Т.о. можно утверждать, что "виртуальность" небольших функций может обойтись сравнительно дорого.

И слово "небольших" здесь не случайно, т.к. уже даже тест с функцией Аккермана (отлично подходящей для выявления относительной стоимости вызова) #include <stdio.h> #include <stdlib.h> #include <time.h>

struct B { int ackf(int x, int y); virtual int vackf(int x, int y); };

struct D : B { int vackf(int x, int y); // замещаем B::vackf };




Содержание  Назад  Вперед