2009-09-07 11 views
6

Mi aplicación utiliza una gran cantidad de objetos Panda. Cada Panda tiene una lista de objetos Bamboo. Esta lista no cambia una vez que se inicializa Panda (no se agregan o eliminan objetos Bamboo). Actualmente, mi clase se lleva a cabo de la siguiente manera:Objetos de longitud variable: ¿Alguna vez una buena idea?

class Panda 
{ 
    int a; 
    int b; 
    int _bambooCount; 
    Bamboo* _bamboo; 

    Panda (int count, Bamboo* bamboo) 
    { 
    _bambooCount = count; 
    _bamboo = new Bamboo[count]; 

    // ... copy bamboo into the array ... 
    } 
} 

Para aliviar la sobrecarga de la asignación de un conjunto de objetos Bamboo, pude poner en práctica esta clase de la siguiente manera - básicamente, en lugar de crear objetos a través del constructor regular, una construcción método asigna un único bloque de memoria para contener tanto el objeto Panda y su Bamboo matriz:

class Panda 
{ 
    int a; 
    int b; 

    Panda() 
    { 
     // ... other initializations here ... 
    } 

    static Panda *createPanda (int count, Bamboo* bamboo) 
    { 
    byte* p = new byte[sizeof(Panda) + 
     sizeof(Bamboo) * count]; 
    new (p) Panda(); 

    Bamboo* bamboo = (Bamboo*) 
     p + sizeof(Panda); 

    // ... copy bamboo objects into the memory 
     // behind the object... 

     return (Panda*)p; 
    } 
} 

¿se puede prever algún problema con el segundo diseño, que no sea el mayor esfuerzo de mantenimiento? ¿Es este un patrón de diseño aceptable, o simplemente una optimización prematura que podría volver a morderme más tarde?

+0

Se va a morder. Y morderá duro. –

+1

Estás rompiendo la mayoría de la semántica para los tipos de clase en C++. Los objetos de longitud variable no existen en C++. – jalf

+2

Si usted está interesado en los cortes de ojo-riego de esta naturaleza, también al igual que al echar un vistazo a las plantillas TBuf8 y TBuf16 clase de Symbian/C++. –

Respuesta

9

C++ le ofrece otra opción. Debes considerar usar std :: vector.

class Panda 
{ 
    int a; 
    int b; 
    std::vector<Bamboo> bamboo; 
    // if you do not want to store by value: 
    //std::vector< shared_ptr<Bamboo> > bamboo; 

    Panda (int count, Bamboo* bamb) : bamboo(bamb, bamb+count) {} 
} 

Si desea almacenar Panda y bambúes en la memoria continua se puede utilizar una solución de this article. La idea principal es sobrecargar operator new y operator delete.

+0

Debe tener en cuenta los efectos secundarios de este tipo de soluciones y los problemas que tendrá que enfrentar: los usuarios no podrán usar los objetos dentro de los contenedores (notablemente std :: vector que preasigna memoria de acuerdo con el tamaño de del tipo en el pasado) Este engaño se endup con código que no sólo es difícil de mantener (el interrogador sabe), pero poco natural a utilizar –

+0

el más natural es el uso de 'std :: vECTOR'. Todas las demás soluciones tienen un uso muy limitado y deben aplicarse con precaución. –

+0

Si no me equivoco, la implementación de cadenas de GCC usa este tipo de engaños. El truco es que el objeto Panda puede contener un solo puntero a la clase de implementación (sobreasignada). – UncleBens

1

Utiliza el aspecto "nuevo" del nuevo operador. Es totalmente correcto relativo a Panda, pero ¿por qué no usas el inicializador de Bamboo?

4

Te morderán si alguien toma un Panda por valor, p. Ej.

//compiler allocates 16-bytes on the stack for this local variable 
Panda panda = *createPanda(15, bamboo); 

Puede ser aceptable (pero es muy probablemente una optimización prematura y horrible) si solamente siempre se refieren a las cosas por el puntero y nunca por valor, y si Cuidado con el constructor de copia y el operador de asignación.

3

Según mi experiencia, la optimización prematura siempre es "prematura" ... Es decir, debe perfilar su código y determinar si hay una necesidad de optimización o si simplemente está creando más trabajo para usted en el largo plazo.

Además, me parece que las preguntas sobre si la optimización vale la pena o no depende en gran medida del tamaño de la clase Bamboo y el número promedio de objetos de bambú por Panda.

3

Esto fue encontrado en C.
Pero en C++ no hay una necesidad real.

La verdadera pregunta es ¿por qué quieres hacer esto?

Esta es una optimización prematura, solo use std :: vector <> internamente y todos sus problemas desaparecerán.

Puesto que está utilizando un puntero RAW internamente que la clase propietaria que se necesita para anular las versiones predeterminadas de:

  • constructor por defecto
  • Destructor
  • constructor de copia
  • Operador de asignación
7

¿Cómo podemos convencer a la gente que en la sencillez de programación y la claridad -en suma: lo que los matemáticos llaman "elegancia" - no es un lujo prescindible, sino un asunto crucial que decide entre el éxito y el fracaso.

- Edsger Dijkstra

+0

Simplemente no lo hagas. Muchas cosas pueden salir mal ... ¿cómo vas a implementar constructores de copia, asignación, destructores? ¿Cómo vas a tratar con los usuarios que quieren tener matrices de Panda? –

+0

Los matemáticos no tienen idea de la programación y el mundo real. – Lothar

2

Si estás tan desesperada, es probable que pueda hacer algo como esto:

template<std::size_t N> 
class Panda_with_bamboo : public Panda_without_bamboo 
{ 
    int a; 
    int b; 
    Bamboo bamboo[N]; 
} 

Pero cree que no está desesperado, pero la optimización prematura.

Cuestiones relacionadas