2010-12-04 11 views
16

Si tengo una clase define como tal:sobrecarga de crear una nueva clase

class classWithInt 
{ 
public: 
    classWithInt(); 
... 
private: 
    int someInt; 
... 
} 

y que someInt es la una y sólo una variable miembro en classWithInt, cuánto más lenta sería declarar una nueva instancia de esta clase que simplemente declarar un nuevo entero?

¿Qué pasa cuando tienes, digamos 10 tales enteros en la clase? 100?

+9

Las clases son The Devil. Nunca deberías usarlos. Todo su código debe estar en un único y enorme módulo con muchas funciones, y debe usar tipos simples en variables globales. En una nota relacionada; Debo dejar de visitar este sitio cuando me siento especialmente sarcástico. : p –

+0

¿Por qué no intentar crear 100 clases y 100 ints? ¡o incluso un millón de ints! – PostMan

+0

¿Lo has probado y perfilado? ¿Por qué eso importa? ¿Por qué harías esto? Apuesto a que es cientos de veces más lento, pero tu compilador PODRÍA hacer algunas cosas elegantes. ¿Qué caso de uso tienes que lo haga relevante? – Falmarri

Respuesta

37

Con un compilador no escrito por estudiantes universitarios borrachos en las primeras horas de la mañana, la sobrecarga es cero. Al menos hasta que comience a poner en virtual funciones; entonces debe pagar el costo del mecanismo de despacho virtual. O si tiene datos no en la clase, en cuyo caso la clase aún debe ocupar algo de espacio (lo que a su vez se debe a que cada objeto debe tener una dirección única en la memoria).

Las funciones no forman parte del diseño de datos del objeto. Son solo una parte del concepto mental del objeto. La función se traduce en un código que toma una instancia del objeto como un parámetro adicional, y las llamadas a la función miembro se traducen de manera correspondiente para pasar el objeto.

La cantidad de miembros de datos no es importante. Compare las manzanas con las manzanas; si tienes una clase con 10 entradas, ocupará el mismo espacio que 10 ints.

La asignación de elementos en la pila es efectivamente gratuita, sin importar cuáles sean. El compilador suma el tamaño de todas las variables locales y ajusta el puntero de la pila de una vez para dejar espacio para ellas. Asignando espacio en los costos de memoria, pero el costo probablemente dependerá más del número de asignaciones que de la cantidad de espacio asignado.

+1

+1 ¡excelente respuesta! –

+0

Te amo por eso. –

+1

Respuesta perfecta. –

7

bueno, vamos a probarlo todo. Puedo compilar, con optimizaciones completos, un ejemplo más completo de este modo:

void use(int &); 

class classWithInt 
{ 
public: 
    classWithInt() : someInt(){} 
    int someInt; 
}; 
class podWithInt 
{ 
public: 
    int someInt; 
}; 

int main() { 
    int foo; 
    classWithInt bar; 
    podWithInt baz; 

    use(foo); 
    use(bar.someInt); 
    use(baz.someInt); 

    return 5; 

} 

Y esta es la salida que recibo de gcc-llvm

; ModuleID = '/tmp/webcompile/_21792_0.bc' 
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" 
target triple = "x86_64-linux-gnu" 

%struct.classWithInt = type { i32 } 

define i32 @main() { 
entry: 
    %foo = alloca i32, align 4      ; <i32*> [#uses=1] 
    %bar = alloca %struct.classWithInt, align 8  ; <%struct.classWithInt*> [#uses=1] 
    %baz = alloca %struct.classWithInt, align 8  ; <%struct.classWithInt*> [#uses=1] 
    %0 = getelementptr inbounds %struct.classWithInt* %bar, i64 0, i32 0 ; <i32*> [#uses=2] 
    store i32 0, i32* %0, align 8 
    call void @_Z3useRi(i32* %foo) 
    call void @_Z3useRi(i32* %0) 
    %1 = getelementptr inbounds %struct.classWithInt* %baz, i64 0, i32 0 ; <i32*> [#uses=1] 
    call void @_Z3useRi(i32* %1) 
    ret i32 5 
} 

declare void @_Z3useRi(i32*) 

Hay algunas diferencias en cada caso. En el caso más simple, el POD type difiere del int plano en una sola forma, requiere una alineación diferente, está alineado en 8 bytes en lugar de solo 4 bytes.

La otra cosa notable es que el POD y el desnudo int no se inicializan. Su almacenamiento se usa justo como está desde el desierto de la pila. El tipo no pod, que tiene un constructor no trivial, hace que se guarde un cero antes de que la instancia se pueda usar para cualquier otra cosa.

+0

No tengo ni idea de cómo leer esta salida. – Andrew

Cuestiones relacionadas