c++ - resueltos - ¿Cuándo es mejor usar la pila en lugar del montón y viceversa?
pilas estructura de datos ejemplos (8)
Como regla general, evite crear objetos grandes en la pila.
- Crear un objeto en la pila lo libera de la carga de recordar limpiar (leer borrar) el objeto. Pero crear demasiados objetos en la pila aumentará las posibilidades de desbordamiento de pila.
- Si usa Heap para el objeto, obtiene la mayor cantidad de memoria que puede proporcionar el sistema operativo, mucho más grande que la pila, pero nuevamente debe asegurarse de liberar la memoria cuando haya terminado. Además, crear demasiados objetos con demasiada frecuencia en el montón tenderá a fragmentar la memoria, lo que a su vez afectará el rendimiento de la aplicación.
En C ++, ¿cuándo es mejor usar la pila? ¿Cuándo es mejor usar el montón?
Esta pregunta está relacionada (aunque no es un engaño) con What and where the stack and heap , que se preguntó hace un par de días.
La pregunta está mal formada.
Hay situaciones donde necesita la pila, otras donde necesita el almacenamiento dinámico, otras donde necesita el almacenamiento estático, otras donde necesita la información de memoria constante, otras donde necesita la tienda gratuita.
La pila es rápida, porque la asignación es solo un "incremento" sobre el SP, y toda la "asignación" se realiza en el momento de invocación de la función en la que se encuentra. La asignación / desasignación del montón (o tienda libre) es más costosa y propensa a errores. .
Una excepción a la regla mencionada anteriormente que generalmente debe usar la pila para variables locales que no son necesarias fuera del alcance de la función:
Las funciones recursivas pueden agotar el espacio de la pila si asignan grandes variables locales o si se invocan recursivamente muchas veces. Si tiene una función recursiva que utiliza memoria, puede ser una buena idea usar memoria basada en pila en lugar de memoria basada en pila.
Use el montón solo para asignar espacio a los objetos en tiempo de ejecución. Si conoce el tamaño en tiempo de compilación, use la pila. En lugar de devolver los objetos asignados por el montón de una función, pase un búfer a la función para que escriba. De esta forma, el búfer puede asignarse donde se llama a la función como una matriz u otra estructura basada en la pila.
Cuantas menos declaraciones malloc () tenga, menos posibilidades habrá de pérdidas de memoria.
Use la pila cuando la memoria utilizada esté estrictamente limitada al ámbito en que la está creando. Esto es útil para evitar fugas de memoria porque sabe exactamente dónde desea usar la memoria y sabe cuándo ya no la necesita, por lo que la memoria se limpiará por usted.
int main()
{
if (...)
{
int i = 0;
}
// I know that i is no longer needed here, so declaring i in the above block
// limits the scope appropriately
}
El montón, sin embargo, es útil cuando se puede acceder a su memoria fuera del alcance de su creación y no desea copiar una variable de pila. Esto puede darle control explícito sobre cómo se asigna y desasigna la memoria.
Object* CreateObject();
int main()
{
Object* obj = CreateObject();
// I can continue to manipulate object and I decide when I''m done with it
// ..
// I''m done
delete obj;
// .. keep going if you wish
return 0;
}
Object* CreateObject()
{
Object* returnValue = new Object();
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn''t go away, its passed back using
// a pointer
}
Obviamente, un problema común aquí es que puede olvidarse de eliminar su objeto. Esto se llama pérdida de memoria. Estos problemas son más frecuentes a medida que su programa se vuelve cada vez menos trivial, donde la "propiedad" (o quién es exactamente el responsable de borrar las cosas) se vuelve más difícil de definir.
Las soluciones más comunes en los lenguajes más administrados (C #, Java) son implementar la recolección de basura para que no tenga que pensar en eliminar cosas. Sin embargo, esto significa que hay algo en el fondo que se ejecuta de forma aperiódica para verificar los datos de tu montón. En un programa no trivial, esto puede volverse bastante ineficaz a medida que aparece un hilo de "recolección de basura" y se escapa, buscando datos que deben eliminarse, mientras que el resto de su programa está bloqueado para ejecutarse.
En C ++, la solución más común y la mejor (en mi opinión) para tratar las pérdidas de memoria es usar un puntero inteligente. El más común de estos es boost::shared_ptr que es ( referencia contada )
Por lo tanto, para recrear el ejemplo anterior boost :: shared_ptr CreateObject ();
int main()
{
boost::shared_ptr<Object> obj = CreateObject();
// I can continue to manipulate object and I decide when I''m done with it
// ..
// I''m done, manually delete
obj.reset(NULL);
// .. keep going if you wish
// here, if you forget to delete obj, the shared_ptr''s destructor will note
// that if no other shared_ptr''s point to this memory
// it will automatically get deleted.
return 0;
}
boost::shared_ptr<Object> CreateObject()
{
boost::shared_ptr<Object> returnValue(new Object());
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn''t go away, its passed back to
// the receiving shared_ptr, shared_ptr knows that another reference exists
// to this memory, so it shouldn''t delete the memory
}
Use la pila cuando su variable no se utilizará después de que la función actual regrese. Use el montón cuando los datos en la variable se necesiten más allá de la duración de la función actual.
como regla general, usa la pila cada vez que puedas. es decir, cuando la variable nunca se necesita fuera de ese alcance.
es más rápido, causa menos fragmentación y evitará los demás gastos generales asociados con llamadas malloc o nuevas. La asignación fuera de la pila es un par de operaciones de ensamblador, malloc o nuevo es varios cientos de líneas de código en una implementación eficiente.
nunca es mejor usar el montón ... solo inevitable. :)