2012-09-08 7 views
11

En el pasado, cada vez que necesitaba crear una instancia de una clase, usaba new para asignarla en el montón (excepto las clases stl y math clases como vec3 y mat4).Cuándo debería asignarse una clase en la pila en lugar del montón

Sin embargo, solo estaba mirando críticamente algunos de mis códigos y me di cuenta de que técnicamente podría estar haciendo estas clases en la pila. No son muy grandes, no necesitan ser modificados fuera de su alcance actual, etc. Cuando yo (ocasionalmente) necesito pasarlos a otra función, puedo usar una referencia tan fácilmente como podría pasar un puntero.

En el pasado, siempre dejé de asignar en el montón, y solo usé la pila en ciertos casos, sin embargo, ahora me pregunto si hubiera sido mejor asignar de forma predeterminada en la pila, y solo usar el montón cuando

  • un puntero es realmente necesario (es decir, el tiempo de vida del objeto a durar más que el alcance de la declaración)
  • la clase o la matriz es demasiado grande para la pila
  • herencia lo requiere (clase base abstracta/interfaz)
  • algo más?

Lo cual también plantea la pregunta: ¿qué tan grande es una clase demasiado grande (más o menos) para asignar razonablemente en la pila? (suponiendo que estamos trabajando, como mínimo, en teléfonos inteligentes y yendo a los escritorios de gama alta) ¿Me estoy preocupando innecesariamente por las restricciones de tamaño de la pila? (Probablemente, siempre y cuando no estemos hablando de grandes matrices, y ninguna clase va a ser ni siquiera cerca de un kilobyte)

+0

Agregaría, cuando desee que la duración del objeto supere el alcance de la declaración. Fuera de su lista, eliminaría todos excepto posiblemente el argumento de tamaño de clase. – juanchopanza

+0

No es una respuesta directa, pero la asignación de la pila tiene algunas ventajas reales sobre la asignación del montón (por ejemplo, velocidad, alcance automático, etc.) [Esta respuesta] (http://stackoverflow.com/a/11044838/195701) enumera algunos de ellos. – Miguel

+0

@juanchopanza Considero que este es uno de los casos en los que 'se necesita realmente un puntero' – zacaj

Respuesta

4

Prefiero asignar en la pila, por dos razones. Primero, todo lo demás es igual, es más rápido que Heap. Además, la desasignación ocurre automáticamente, no necesito recordar delete (por supuesto, hay auto_ptr sy otros para ayudar con eso).

un puntero que realmente se necesita

Está bien para pasar un puntero a un objeto en la pila. Solo asegúrese de que el usuario de ese puntero no acceda al objeto después de que expire su tiempo de vida.

la clase o la matriz es demasiado grande para la pila

Sólo para las cosas realmente grandes se debe esta materia. Probablemente tenga 1MB de pila, por lo que puede colocar alrededor de 1000 objetos de 1KB antes de que haya un problema.

herencia lo requiere

¿Por qué es así?

algo más?

La vida útil requerida del objeto es más larga que la duración del marco de pila. Esta es la razón principal para asignar en el montón.

+0

"¿Por qué lo haría?" - funciones de fábrica que devuelven una clase concreta de diferencia según sus parámetros y/o alguna configuración. No es * exactamente * la herencia que lo requiere, es el hecho de que el usuario solo conoce la clase base. –

+0

@SteveJessop: En ese caso, yo sólo diría que la API lo requiere (todos los constructores, en su caso, son privados). No tiene nada que ver con la herencia. –

+0

@stevejessop esto es más o menos lo que quise decir. Tengo muchas clases base abstractas que tienen muchas implementaciones diferentes, en cuyo caso se necesitaría un puntero – zacaj

-2

Se asigna en el montón solamente cuando se necesita asignar dinámicamente la memoria. Lo que significa que no sabe cuánto necesita asignar en tiempo de compilación. Se asigna en la pila el resto de las veces

+0

-1 para "Lo que significa que no sabe cuánto necesita asignar en tiempo de compilación." Esto es falso El OP ofrece algunas otras situaciones cuando necesita asignar en el montón, como la asignación de algo que es demasiado grande para la pila. Usted puede saber en tiempo de compilación que necesita un arreglo de 10 millones de enteros, pero eso es demasiado grande para la pila en la mayoría de sistemas operativos, por lo que debe asignarlo en el montón. –

+0

-1 Esta no es una buena respuesta, a veces la pila simplemente no será lo suficientemente grande. – mathematician1975

+0

Puede que tenga que pasar el objeto en el sistema, lo que significa que su función devolverá el objeto, pero no va a ser válido más. – roni

7

Su comportamiento predeterminado debería ser:

Si la vida útil del objeto es consistente con un alcance específico
es decir, determina fácilmente en tiempo de compilación

entonces debe ser un objeto duración de almacenamiento automático (apilar como)

Si la vida útil del objeto se define en el tiempo de ejecución y se extiende más allá del alcance actual

entonces debería ser un un objeto de la duración de almacenamiento dinámica (heap como)

Nota: Todos los objetos duración de almacenamiento dinámico deben tener su vida controlada por envolviéndolos en un una clase RAII apropiado. Por lo general, esto significa: Para objetos individuales, un puntero inteligente, mientras que varios objetos terminan en un contenedor.

I odio ver las cosas se define como pila Vs montón. Como no transmite la semántica real de la situación.

int x;  // its on the stack 
struct X 
{ 
    int x; // Is this a stack or heap object? 
}   // It depends on its parent. 


// But in both cases it is an automatic storage duration object. 
// In both cases the lifespan's are well defined. 
//  The first is defined by the scope it is declared within. 
//  The second is defined by the lifespan of its parent. 

Debería pensar en términos de objetos de "duración de almacenamiento" automáticos/dinámicos. Esto transmite la semántica correcta del lenguaje.

Tenga en cuenta que hay otros dos tipos de variables, lo que hace cuatro tipos diferentes de variable. objetos de "duración de almacenamiento" automático/dinámico/estático/hilo.

+0

está utilizando puntos inteligentes prácticamente estándar de la industria para todas las asignaciones dinámicas en la actualidad? – zacaj

+0

@zacaj: Es de esperar (pero no caiga en la trampa de que los indicadores inteligentes son el único mecanismo (piense en contenedores)). Para las personas que escriben C++ real moderno, sí. Pero todavía hay mucha gente que escribe C con un compilador de C++ (también conocido como C-con clases). Pero todas las buenas excepciones del código seguro de C++ se escriben usando punteros inteligentes. –

1

¿Cuándo debe asignarse una clase en la pila en lugar del montón?

Siempre que sea posible y no un gran inconveniente. Habrá excepciones, pero para responder a su pregunta como una regla general: Al crear una instancia, new/new[] debe ser tipeado menos del uno por ciento del tiempo.


un puntero es realmente necesario (es decir, el tiempo de vida del objeto a durar más que el alcance de la declaración)

Sí, en los casos apropiados. A juzgar por su uso del montón descrito en el OP, es probable que esto sea necesario con mucha menos frecuencia de lo que cree.

la clase o la matriz es demasiado grande para la pila

Sí, pero que no debería ser una gran preocupación - una clase que normalmente grande indica que algo está fundamentalmente mal con tu clase Las clases amigables para el cliente podrían considerar la creación de esas enormes matrices de tamaño fijo en el montón.

herencia lo requiere (clase base abstracta/interfaz)

En algunos casos (por ejemplo, cuando está presente una fábrica de extracto o profunda clon de tipo polimórfico), pero entonces es el fábrica que crea el tipo, y el problema a menudo se aleja del uso de la pila por parte de tu programa antes de que puedas considerarlo.

algo más?

No hay


Las razones:

  • está claro, sucinto, y su vida útil y el alcance son bien determinada.
  • menos consumo de recursos.
  • menos errores relacionados con la memoria o cosas que podrían salir mal.
  • velocidad. la asignación de la pila es muy rápida. menos cerraduras.
Cuestiones relacionadas