¿Cómo funciona el montón en c ++
los montón
Conteúdo
Así como es posible pasar un puntero a una función, es posible para una función para devolver un puntero. Una función que devuelve la dirección de una doble está declarada como sigue:
doble * fn (void) -
Sin embargo, debe tener mucho cuidado al devolver un puntero. Para entender los peligros, debe saber algo de alcance variable.
Alcance limitado en C ++
Shacer frente a es el rango sobre el cual se define una variable. Considere el siguiente fragmento de código:
// La siguiente variable es accesible a // todas las funciones y se define como el tiempo que el programa se está ejecutando // (alcance global) int intGlobal - // el siguiente intChild variable es accesible // sólo a la función y se define solamente // siempre que C ++ es hijo de ejecutar () o una función // qué niño () llama (ámbito de la función) vacío niño (void) {int intChild -} // el siguiente intParent variable tiene la función // padres scopevoid (void) {int intParent = 0-infantil () - int intLater = 0-intParent = intLater-} int main (int nargs, char * pargs []) {parent () -}
Este fragmento de programa se inicia con la declaración de una variable intGlobal. Esta variable existe desde el momento en que el programa comienza a ejecutar hasta que se termina. Tu dices eso intGlobal " tiene alcance del programa ". También dice que la variable " entra en el alcance " incluso antes de la función main () se llama.
La funcion main () invoca inmediatamente parent (). La primera cosa que el procesador ve en parent () es la declaración de intParent. A este punto, intParent entra en el alcance - es decir, intParent se define y disponible para el resto de la función de parent ().
La segunda declaración en parent () es la llamada a niño (). Una vez más, la función de niño () declara una variable local, esta vez intChild. El alcance de la variable intChild se limita a la función de niño (). Técnicamente, intParent no se define dentro del alcance de niño () porque niño () no tiene acceso a intParent- sin embargo, la variable intParent continúa existiendo mientras niño () es la ejecución.
Cuando niño () salidas, la variable intChild sale del ámbito. No sólo es intChild ya no es accesible, ya no existe. (La memoria ocupada por intChild se devuelve a la piscina en general a ser utilizado para otras cosas.)
Como parent () continúa la ejecución, la variable intLater entra en el alcance de la declaración. En el punto de que parent () regresa a main (), ambas cosas intParent y intLater ir fuera de alcance.
Porque intGlobal se declara a nivel mundial en este ejemplo, está disponible para las tres funciones y permanece disponible para la vida del programa.
Examinar el problema alcance en C ++
El siguiente segmento de código se compila sin errores pero no funciona (no te odio, que?):
doble * niño (void) {double dLocalVariable retorno dLocalVariable-} void padre (void) {double * pdLocal-pdLocal = niño () - * pdLocal = 1.0-}
El problema con esta función es que dLocalVariable se define sólo en el ámbito de la función niño (). Por lo tanto, en el momento en la dirección de memoria de dLocalVariable se devuelve desde niño (), se refiere a una variable que ya no existe. La memoria que dLocalVariable anteriormente ocupado probablemente está siendo utilizado para otra cosa.
Este error es muy común, ya que puede arrastrarse para arriba en un número de maneras. Desafortunadamente, este error no causa el programa para detener instantáneamente. De hecho, el programa puede funcionar bien la mayor parte del tiempo - es decir, el programa continúa trabajando, siempre y cuando la memoria anteriormente ocupada por dLocalVariable no se reutiliza inmediatamente. Tales problemas intermitentes son los más difíciles de resolver.
Proporcionar una solución utilizando el montón en C ++
El problema se originó alcance porque C ++ recuperó la memoria definido localmente antes de que el programador estaba listo. Lo que se necesita es un bloque de memoria controlada por el programador. Ella puede asignar la memoria y poner de nuevo cuando quiere - no porque C ++ piensa que es una buena idea. Un bloque de la memoria Tal es llamado el montón.
Montón de memoria se asigna mediante el nuevo palabra clave seguida por el tipo de objeto a asignar. los nuevo comando rompe un trozo de memoria fuera del montón lo suficientemente grande como para contener el tipo específico de objeto y devuelve su dirección. Por ejemplo, el siguiente asigna una doble variables de la pila:
doble * niño (void) {double * pdLocalVariable = new doble retorno pdLocalVariable-}
Esta función ahora funciona correctamente. Aunque la variable pdLocalVariable sale del ámbito cuando la función niño () devoluciones, la memoria a la que pdLocalVariable se refiere no es así. Una ubicación de memoria devuelto por nuevo no salir del alcance hasta que se devuelve de forma explícita a la pila usando la palabra clave borrar, que está diseñado específicamente para ese propósito:
void padre (void) {// niño () devuelve la dirección de un bloque de // de memorydouble montón * pdMyDouble = niño () - // almacenar un valor no * pdMyDouble = 1,1 - // ... // ahora devolver el memoria al heapdelete pdMyDouble-pdMyDouble = 0 - // ...}
Aquí el puntero devuelto por niño () se utiliza para almacenar un valor doble. Después de la función se terminó con la posición de memoria, se devuelve a la pila. La funcion parent () establece el puntero a 0 después de que la memoria de almacenamiento dinámico se ha vuelto - esto no es un requisito, pero es una muy buena idea.
Si el programador intenta erróneamente para almacenar algo en * PdMyDouble después de la borrar, el programa se bloqueará de inmediato con un mensaje de error significativo.
Puedes usar nuevo asignar matrices del montón también, pero debe devolver una matriz utilizando el delete [] palabra clave:
int * nArray = new int [10] -nArray [0] = 0-delete [] nArray-
Técnicamente new int [10] invoca el nuevo [] operador pero funciona igual que nuevo.