Escribí un ejemplo simple, que estima el tiempo promedio de llamada de la función virtual, utilizando la interfaz de clase base y dynamic_cast y llamada de la función no virtual. aquí es que:¿Por qué la llamada a función virtual es más rápida que dynamic_cast?
#include <iostream>
#include <numeric>
#include <list>
#include <time.h>
#define CALL_COUNTER (3000)
__forceinline int someFunction()
{
return 5;
}
struct Base
{
virtual int virtualCall() = 0;
virtual ~Base(){};
};
struct Derived : public Base
{
Derived(){};
virtual ~Derived(){};
virtual int virtualCall(){ return someFunction(); };
int notVirtualCall(){ return someFunction(); };
};
struct Derived2 : public Base
{
Derived2(){};
virtual ~Derived2(){};
virtual int virtualCall(){ return someFunction(); };
int notVirtualCall(){ return someFunction(); };
};
typedef std::list<double> Timings;
Base* createObject(int i)
{
if(i % 2 > 0)
return new Derived();
else
return new Derived2();
}
void callDynamiccast(Timings& stat)
{
for(unsigned i = 0; i < CALL_COUNTER; ++i)
{
Base* ptr = createObject(i);
clock_t startTime = clock();
for(int j = 0; j < CALL_COUNTER; ++j)
{
Derived* x = (dynamic_cast<Derived*>(ptr));
if(x) x->notVirtualCall();
}
clock_t endTime = clock();
double callTime = (double)(endTime - startTime)/CLOCKS_PER_SEC;
stat.push_back(callTime);
delete ptr;
}
}
void callVirtual(Timings& stat)
{
for(unsigned i = 0; i < CALL_COUNTER; ++i)
{
Base* ptr = createObject(i);
clock_t startTime = clock();
for(int j = 0; j < CALL_COUNTER; ++j)
ptr->virtualCall();
clock_t endTime = clock();
double callTime = (double)(endTime - startTime)/CLOCKS_PER_SEC;
stat.push_back(callTime);
delete ptr;
}
}
int main()
{
double averageTime = 0;
Timings timings;
timings.clear();
callDynamiccast(timings);
averageTime = (double) std::accumulate<Timings::iterator, double>(timings.begin(), timings.end(), 0);
averageTime /= timings.size();
std::cout << "time for callDynamiccast: " << averageTime << std::endl;
timings.clear();
callVirtual(timings);
averageTime = (double) std::accumulate<Timings::iterator, double>(timings.begin(), timings.end(), 0);
averageTime /= timings.size();
std::cout << "time for callVirtual: " << averageTime << std::endl;
return 0;
}
Parece que callDynamiccast lleva casi dos veces más.
time for callDynamiccast: 0.000240333
time for callVirtual: 0.0001401
Cualquier idea por qué lo hace?
EDITADO: la creación de objetos se realiza ahora en la función separada, por lo que el complemento no la conoce como tipo real. Casi el mismo resultado.
EDITED2: crea dos tipos diferentes de objetos derivados.
Probablemente necesite ejecutar muchas más iteraciones para obtener una medida estadística decente. ¿Está compilando en la configuración de optimización más alta? –
Lo intenté con muchas más iteraciones, pero el resultado es el mismo. Todas las optimizaciones están desactivadas. Usé MSVS2008. –
Su prueba no es válida, porque el compilador puede optimizar fácilmente tanto la llamada virtual (en una llamada no virtual) como la dinámica_cast (básicamente en un noop), porque sabe que 'ptr' realmente apunta a un objeto' Derived'. –