En C++, ¿cuándo es mejor usar la pila? ¿Cuándo es mejor usar el montón?¿Cuándo es mejor usar la pila en lugar del montón y viceversa?
Respuesta
Utilice 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.
Sin embargo, hay formas de evitarlo. Pasar un búfer a una función que luego le escribe datos es una buena manera de que una función "devuelva" datos dinámicos que permanecen en un marco de pila inferior. Es menos parecido a OO, pero es mucho más eficiente. –
El tamaño también es una consideración: todo lo que supere 1K en la pila debe considerarse cuidadosamente. A veces es mejor tener un puntero de pila para acumular memoria (junto con la expresión 'Adquisición de recursos es inicialización') – Arkadiy
Pero, ¿qué ocurre cuando la memoria es propiedad de una clase? ¿Cómo se decide cuándo una propiedad de clase debe ser un puntero o no? ¿También cuándo podría usar un puntero inteligente? – JagWire
Utilice el montón para asignar espacio únicamente 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, menores serán las posibilidades de pérdida de memoria.
Esta pregunta está relacionada (aunque no es realmente una tontería) con What and where are the stack and heap, que se le preguntó hace un par de días.
La pregunta está mal formada.
Hay situaciones en las que necesita la pila, otras donde necesita el montón, otras donde necesita el almacenamiento estático, otras donde necesita los datos 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 es más tiempo caro y propenso a errores.
Como regla general, evite crear objetos grandes en la pila.
- Crear un objeto en la pila le 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 el sistema operativo puede proporcionar, 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.
Utilice 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 la memoria se puede acceder fuera del alcance de su creación y no se 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 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 deberían 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 hacer frente a fugas de memoria es utilizar un puntero inteligente. La más común de ellas es que es boost::shared_ptr (reference counted)
Así que para recrear el ejemplo anterior CreateObject impulso :: shared_ptr();
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
}
Y luego hubo semántica de movimiento –
como regla general, utilice la pila cada vez que pueda. es decir, cuando la variable nunca se necesita fuera de ese alcance.
es más rápido, causa menos fragmentación y va a evitar los otros gastos generales asociados con la llamada malloc o nueva. 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. :)
Es mejor que un par de operaciones de ensamblador: es solo un agregado o resta (dependiendo de en qué dirección crezca su pila). – Eclipse
agrega y resta no siempre son operaciones individuales ... pero también considera la limpieza en el otro extremo. Dependiendo de la convención de llamadas, habrá un sub/agregar para que coincida con el add/sub, aunque todos pueden combinarse dependiendo de cómo se usa exactamente la pila y qué optimizaciones hace el compilador (en realidad puede reducirse a cero instrucciones. .. o en casos muy especiales, menos las instrucciones) – jheriko
Una excepción a la regla mencionada anteriormente que por lo general debe utilizar la pila para las variables locales que no son necesarios fuera del ámbito de la función:
funciones recursivas pueden agotar el espacio de pila si se asignan local grande variables 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.
- 1. ¿Cuándo debería usar NSURL en lugar de NSString y viceversa?
- 2. Cuándo debería asignarse una clase en la pila en lugar del montón
- 3. ¿Cuándo es mejor usar zip en lugar de izip?
- 4. ¿Cuándo es mejor usar un vector que una matriz y viceversa en Java?
- 5. Cuándo usar HashMap sobre LinkedList o ArrayList y viceversa
- 6. pila y montón en V8 (JavaScript)
- 7. ¿Cuándo uso PHP_EOL en lugar de \ n y viceversa? Ajax/Jquery problema del cliente
- 8. ¡La asignación de la pila falla y la asignación del montón tiene éxito! ¿Es posible?
- 9. ¿Cuándo debería usar un TreeMap sobre PriorityQueue y viceversa?
- 10. ¿Por qué la memoria se divide en pila y montón?
- 11. Asignación de memoria del montón y pila de Java
- 12. montón y pila de ensamblaje de Windows?
- 13. ¿Cuándo es mejor usar un Struct en lugar de un Hash en Ruby?
- 14. Cuándo usar dup, y cuándo usar clon en Ruby?
- 15. ¿Cuándo es el método de fábrica mejor que simple de fábrica y viceversa?
- 16. Cuándo usar `static_assert` en lugar de SFINAE?
- 17. ¿Cuándo es correcto usar ViewData en lugar de ViewModels?
- 18. ¿Cuándo debería usar Perl CGI en lugar de PHP (o viceversa)?
- 19. Cuándo usar HttpApplicationState en lugar de Web.Caching.Cache?
- 20. ¿Por qué querrías asignar memoria en el montón en lugar de la pila?
- 21. contenedores STL en la pila y el montón
- 22. Creación de matriz de objetos en la pila y montón
- 23. ¿Cuándo usar == y cuándo usarlo?
- 24. ¿Cómo creo una matriz en C++ que está en el montón en lugar de la pila?
- 25. Asignación estática en java - montón, pila y generación permanente
- 26. ¿Cuándo debería usar el doble en lugar del decimal?
- 27. ¿Cómo sé cuál es el mejor lugar para usar 'usar'?
- 28. ¿Cuál es la mejor pila Java SIP?
- 29. ¿Cuándo es mejor no usar la unión interna?
- 30. ¿Cuándo usar 'función' en lugar de 'diversión'?
Supongo que quiere decir la pila de sistema y el montón de sistema para asignar memoria, no el montón de estructuras de datos y la pila, ¿es correcto? –