16

Estaba leyendo sobre la Optimización de base vacía (EBO). Mientras lee, las siguientes preguntas aparecieron en mi mente:Cuando los programadores usan Empty Base Optimization (EBO)

  1. ¿Cuál es el punto de utilizar clase vacía como clase base cuando no contribuye en nada a las clases derivadas (ni funcionalidad-sabio, ni datos en cuanto a)?

  2. En this article, leí esto:

// S es struct
clase vacía T: S
{
            int x;
};

[...]

en cuenta que no hemos perdido ningún dato o precisión código: cuando se crea un objeto independiente de tipo S, el tamaño del objeto sigue siendo de 1 (o más) como antes; solo cuando S se utiliza como base clase de otra clase su memoria se contrae a cero. Para realizar el impacto de este ahorro, imagine un vector que contiene 125,000 objetos. ¡El EBO solo ahorra la mitad de un megabyte de memoria !

¿Quiere decir que si no usamos "S" como clase base de la "T", nos necesariamente consumir el doble de megabyte de memoria? Creo que el artículo compara dos escenarios diferentes que no creo que sean correctos.

me gustaría saber un escenario real cuando EBO pueden demostrado ser útiles. (Medios, en el mismo escenario, tendríamos necesariamente estar en pérdida si no usamos EBO!).

Tenga en cuenta que si su respuesta contiene explicaciones como esta:

El punto es que una clase vacía tiene el tamaño no es cero, pero cuando deriva o se deriva que puede tener un tamaño de cero, entonces no te pido eso, como ya lo sé. Mi pregunta es, ¿por qué alguien derivaría su clase de una clase vacía en primer lugar? Incluso si él no deriva y simplemente escribe su clase (sin ninguna base vacía), ¿está en la pérdida de CUALQUIER manera?

+0

@Suma ... ¿qué cambiaste en mi publicación? : -/.. No puedo entender ... – Nawaz

+0

¿Por qué dices que la clase base no aporta nada funcionalmente? – jalf

+0

@jalf ... hasta ahora no vi ningún ejemplo ... por cierto, por funcionalidad me refiero a funciones que hacen algo, en lugar de nada – Nawaz

Respuesta

28

EBO es importante en el contexto de policy based design, donde generalmente hereda en privado de varias clases de política.Si tomamos el ejemplo de una política de seguridad de los subprocesos, uno podría imaginar el pseudo-código:

class MTSafePolicy 
{ 
public: 
    void lock() { mutex_.lock(); } 
    void unlock() { mutex_.unlock(); } 

private: 
    Mutex mutex_; 
}; 

class MTUnsafePolicy 
{ 
public: 
    void lock() { /* no-op */ } 
    void unlock() { /* no-op */ } 
}; 

Dada una política de clase-diseño basado tales como:

template<class ThreadSafetyPolicy> 
class Test : ThreadSafetyPolicy 
{ 
    /* ... */ 
}; 

Utilización de la clase con un MTUnsafePolicy simplemente no agregue ningún tamaño sobre la clase Test: es un ejemplo perfecto de no pague por lo que no usa.

+0

@icecrime .... gracias por este ejemplo increíble ... +1 de mí ... – Nawaz

6

EBO no es realmente una optimización (al menos no una que haga en el código). El punto es que una clase vacía tiene un tamaño distinto de cero, pero cuando se deriva o deriva puede tener un tamaño cero.

Este es el resultado más habitual:

class A { }; 
class B { }; 

class C { }; 
class D : C { }; 

#include <iostream> 
using namespace std; 

int main() 
{ 
     cout << "sizeof(A) + sizeof(B) == " << sizeof(A)+sizeof(B) << endl; 
     cout << "sizeof(D) == " << sizeof(D) << endl; 

     return 0; 
} 

Salida:

sizeof(A) + sizeof(B) == 2 
sizeof(D) == 1 

Para la edición: La optimización es, que si usted hace realmente se derivan (por ejemplo, de un funtor, o de una clase que tiene solo miembros estáticos), el tamaño de su clase (que se deriva) no aumentará en 1 (o más probablemente 4 u 8 debido a los bytes de relleno).

+0

@Let_Me_Be ... He editado mi pregunta ... por favor vuelve a verla ... Espero que entiendas ahora lo que estoy pidiendo. :-) – Nawaz

+0

@Nawaz He editado mi respuesta. –

+0

@Let_Me_Be ... gracias por esta actualización ... eso tiene sentido ahora ... estoy buscando más respuesta ... con más escenarios .. – Nawaz

0

EBO no es algo que el programador influye, y/o el programador sería castigado si eligiera no derivar de una clase base vacía.

Los controles del compilador ya sea para:

class X : emptyBase { int X; }; 
class Y { int x }; 

se obtiene sizeof(X) == sizeof(Y) o no. Si lo hace, el compilador implementa EBO, si no, no lo hace.

Nunca ocurre una situación en la que sizeof(Y) > sizeof(X) ocurra.

0

La mayoría de las veces, una clase base vacía se usa polimórficamente (que el artículo menciona), como clases de "etiqueta" o como clases de excepción (aunque normalmente se derivan de std :: exception, que no está vacía) A veces hay una buena razón para desarrollar una jerarquía de clases que comienza con una clase base vacía.

Boost.CompressedPair utiliza el EBO para reducir el tamaño de los objetos en caso de que uno de los elementos esté vacío.

+0

no tengo idea de por qué esto se ha votado negativamente, me parece bien. –

1

EASTL tiene una buena explicación de por qué necesitaban EBO, su también explica en profundidad en el documento que enlazan a/de crédito

+0

... el artículo es demasiado grande ... Lo leeré cuando tenga suficiente tiempo ... luego lo comentaré ...: -) ... gracias por el link por cierto. – Nawaz

-1

El principal beneficio que se me ocurre es moldeado dinámico. Puede tomar un puntero a S e intentar hacer dynamic_cast sobre cualquier cosa que herede de S, suponiendo que S ofrezca una función virtual como un destructor virtual, que prácticamente debe hacer como clase base. Si estuvieras, por ejemplo, implementando un lenguaje de tipado dinámico, es posible que desees o necesites que cada tipo proceda de una clase base puramente para fines de almacenamiento borrado por tipo y comprobación de tipo a través de dynamic_cast.

+1

.. si S tiene funciones virtuales ... ¡lo más probable es que no sea una clase vacía! – Nawaz

+0

@Nawez: ¿Por qué no? La clase base S bien podría ofrecer implementaciones no operativas, o incluso virtuales puras. Mire la respuesta de Icecrime; podría decirse que 'lock' debería haber sido virtual. – MSalters

+1

@MSalters ... si una clase tiene funciones virtuales, es decir, su tamaño no puede ser cero (al menos para los compiladores de la vida real) ... y en cuanto a la respuesta de icecrime, ¡la cerradura no virtual funcionaría perfectamente! – Nawaz

4

La "Optimización" en el EBO significa que el caso cuando se utiliza la clase base se puede optimizar para usar menos memoria que si usa un miembro del mismo tipo. Es decir. se compara

struct T : S 
{ 
     int x; 
}; 

con

struct T 
{ 
     S s; 
     int x; 
}; 
no

con

struct T 
{ 
     int x; 
}; 

Si su pregunta es ¿por qué tener una clase vacía del todo (ya sea como miembro, o como base) , es porque usas sus funciones miembro. Vacío significa que no tiene ningún miembro de datos, no es que no tenga ningún miembro. Este tipo de cosas a menudo se realizan al programar con plantillas, donde la clase base a veces está "vacía" (sin miembros de datos) y otras no.

4

Su utilizarse cuando los programadores quieren exponer algunos datos al cliente sin aumentar el tamaño de la clase del cliente. La clase vacía puede contener enums y typedefs o alguna define lo que el cliente puede usar. La forma más juiciosa de usar dicha clase es heredar dicha clase de forma privada. Esto ocultará los datos del exterior y no aumentará el tamaño de tu clase.

Cuestiones relacionadas