2009-02-27 9 views
9

¿Se considera mala educación/mala práctica colocar explícitamente miembros de objeto en el montón (a través de nuevo)? Creo que es posible que desee permitir que el cliente elija la región de memoria para crear una instancia del objeto. Sé que podría haber una situación en la que los miembros de Heap sean aceptables. Si conoce una situación, ¿podría describirla, por favor?C++ Etiqueta sobre las variables de miembro en el montón

+0

¿Qué quiere decir con "quiere permitir que el cliente elija"? –

+0

Deje que quienquiera que esté usando la clase defina dónde se coloca la instancia en la memoria. I.E .: ClassICreated client_obj = new ClassICreated;/* o */ClassICreated client_obj; – bluehavana

+0

Pregunta sobre * variables de miembro * y dónde se ponen en la memoria. Si asigna una pila a un Foo: Foo foo; Los miembros del puntero Foo pueden ir en el montón sin que el usuario lo espere. Puede permitir que el usuario especifique un asignador para evitar esto. – tgamblin

Respuesta

13

Si tiene una clase que está diseñada para la semántica de copia y está asignando/desasignando innecesariamente un montón de memoria, podría ver que esto es una mala práctica. En general, sin embargo, no lo es. Hay muchas clases que pueden hacer uso del almacenamiento en montón. Solo asegúrate de no tener pérdidas de memoria (desasignar elementos en el destructor, recuento de referencias, etc.) y estarás bien.

Si desea más flexibilidad, considere dejar que su usuario especifique un Allocator. Lo explicaré.

Determinadas clases, p. Ej. std::vector, cadena, mapa, etc. necesita almacenamiento de montón para las estructuras de datos que representan. No se considera malos modales; Cuando usted tiene una asignada automáticamente vector, se espera que el usuario conozca que un buffer se asigna cuando el constructor vector se llama:

void foo() { 
    // user of vector knows a buffer that can hold at least 10 ints 
    // gets allocated here. 
    std::vector<int> foo(10); 
} 

mismo modo, para std::string, usted sabe que hay una interna, montón asignados char*. Si hay una instancia por cada string suele estar a la altura de la implementación de STL; muchas veces son referencia contada.

Sin embargo, para casi todas las clases de STL, los usuarios hacen tienen una opción de dónde se colocan las cosas, en el sentido de que pueden especificar un asignador. vector se define la clase de la siguiente manera:

template <typename T, typename Alloc = DefaultAllocator<T> > 
class vector { 
    // etc. 
}; 

Internamente, vector utiliza Alloc (que por defecto es a lo que el asignador por defecto es para T) para asignar el almacenamiento intermedio y otro montón de almacenamiento que puede necesitar. Si los usuarios no le gusta la estrategia de asignación por defecto, pueden especificar uno de los suyos:

vector<int, MyCustomAllocator> foo(10); 

Ahora, cuando el constructor asigna, se utilizará un MyCustomAllocator en lugar del predeterminado. Aquí hay algunos details on writing your own STL allocator.

Si le preocupa que pueda ser de "mala educación" usar el montón para cierto almacenamiento en su clase, puede considerar dar a los usuarios de su clase una opción como esta para que puedan especificar cómo son las cosas para ser asignado si su estrategia predeterminada no se ajusta a sus necesidades.

+0

Yo te votaría, pero no tengo el representante.Hasta ahora, esta es una gran respuesta, gracias. – bluehavana

+0

Esta respuesta y la respuesta de Matt Davis merecen ser aceptadas. Como no se gana ningún Rep desde la aceptación, solo podemos llamar a ambos respuestas excelentes. Muchas gracias. – bluehavana

0

hmm, realmente no entiendo su pregunta.

Si usted tiene una clase:

class MyOtherClass; 
class MyClass 
{ 
    MyOtherClass* m_pStruct; 
}; 

continuación, el cliente de MiClase no tener una opción real de cómo se asignará m_pStruct.

Pero será la decisión del cliente de cómo será en sí se asignará la clase MyClass, ya sea en la pila o en el montón:

MyClass* pMyClass = new MyClass; 

o

MyClass myClass; 
1

donde la clase pone su miembros es menos importante que la administración de ellos está contenida dentro de la clase; es decir, los clientes y las subclases no deberían tener que preocuparse por la variable miembro del objeto.

La forma más sencilla de hacer esto sería convertirlos en variables de pila. Pero en algunos casos, como si tu clase tiene una estructura de datos dinámica como una lista vinculada, no tiene sentido.

Pero si se asegura de que sus objetos se limpien después de themeselves, eso debería estar bien para la mayoría de las aplicaciones.

10

No lo considero una mala práctica en absoluto. Hay todo tipo de razones por las que es posible que desee asignar explícitamente una variable miembro a través de nuevo. Aquí hay algunos fuera de mi cabeza.

  • Supongamos que su clase tiene un búfer muy grande, por ejemplo, 512kb o 1MB. Si este búfer no se almacena en el montón, sus usuarios podrían potencialmente exceder el espacio de pila predeterminado si crean múltiples variables locales de su clase. En este caso, tendría sentido asignar el búfer en su constructor y almacenarlo como un puntero.
  • Si está haciendo algún tipo de recuento de referencias, necesitará un puntero para realizar un seguimiento de cuántos objetos apuntan realmente a sus datos.
  • Si su variable miembro tiene una vida útil diferente a la de su clase, un puntero es el camino a seguir. Un ejemplo perfecto de esto es la evaluación perezosa, donde solo paga por la creación del miembro si lo solicita el usuario.
  • Aunque no es necesariamente un beneficio directo para los usuarios, el tiempo de compilación es otra razón para usar punteros en lugar de objetos. Si coloca un objeto en su clase, debe incluir el archivo de encabezado que define el objeto en el archivo de encabezado de su clase. Si usa un puntero, puede reenviar declarar la clase y solo incluir el archivo de encabezado que define la clase en los archivos fuente que lo necesitan. En proyectos grandes, el uso de declaraciones directas puede acelerar drásticamente el tiempo de compilación al reducir el tamaño total de las unidades de compilación.

Por otro lado, si los usuarios crean una gran cantidad de instancias de la clase para su uso en la pila, sería ventajoso el uso de objetos en lugar de punteros para sus variables miembro simplemente porque asignaciones del montón/cancelaciones de asignación son lentos en comparación. Es más eficiente evitar el montón en este caso, teniendo en cuenta la primera viñeta de arriba, por supuesto.

+0

Si pudiera aceptar dos respuestas, aceptaría esto y tgamblin. Gracias por todas las diversas situaciones, todas difieren lo suficiente como para brindarme una visión amplia y pragmática del alcance y las soluciones del problema. – bluehavana

Cuestiones relacionadas