2011-01-14 21 views
7

Estoy confundido acerca de la asignación de memoria en C++ en términos de las áreas de memoria como área de datos Const, Pila, Pila, Freestore, Heap y área Global/Static. Me gustaría entender el patrón de asignación de memoria en el siguiente fragmento. ¿Alguien puede ayudarme a entender esto? Si hay algo más aparte de los tipos de variables mencionados en el ejemplo para ayudar a entender mejor el concepto, por favor modifique el ejemplo.Asignación de memoria en C++

class FooBar 
{ 
     int n; //Stored in stack? 

     public: 

      int pubVar; //stored in stack? 

      void foo(int param) //param stored in stack 
      { 
       int *pp = new int; //int is allocated on heap. 
       n = param; 
       static int nStat; //Stored in static area of memory 
       int nLoc;   //stored in stack? 
       string str = "mystring"; //stored in stack? 
       .. 
       if(CONDITION) 
       { 
        static int nSIf; //stored in static area of memory 
        int loopvar;  //stored in stack 
        .. 
       } 
      } 
} 

int main(int) 
{ 
    Foobar bar; //bar stored in stack? or a part of it? 

    Foobar *pBar; //pBar is stored in stack 

    pBar = new Foobar(); //the object is created in heap? What part of the object is stored on heap 

} 

EDIT:
Lo que me confunde es, si pBar = new Foobar(); almacena el objeto en el montón, ¿cómo es que int nLoc; y int pubVar;, que son componentes del objeto almacenado en la pila? Suena contradictorio para mí. ¿No deberían la vida útil de pubvar y pBar ser la misma?

+0

La mejor idea es dejar de pensar en el montón y la pila. Realmente no existen en C++ (es una construcción Java/C#). Piensa en la duración (duración) de un objeto. –

+2

Waitaminute. La pila es una construcción de Java? Definitivamente no. Es un constructo C, si no es anterior. Pero 'setjmp/longjmp' dejó muy claro que C tiene una pila. Java, por otro lado, permite que los objetos escapen el alcance de la función, por lo que el concepto de pila no existe (memoria wrt; las excepciones son otra cuestión) – MSalters

Respuesta

10

"Montón" y "pila" son términos obsoletos, inexactos y confusos relacionados con la duración del almacenamiento.

Los objetos con "duración de almacenamiento automática" son lo que las personas tontas llaman "objetos de pila". Son los que definirá dentro de una función como "variables locales". Se salen del alcance cuando termina su bloque adjunto.

objetos con "duración de almacenamiento dinámico" son los que se crea en la tienda libre con la ayuda de la palabra clave new (o, si eres tonto, malloc), y luego destruir siempre que lo desee con la palabra clave delete (o, si es tonto, free).

También hay objetos con "duración de almacenamiento estático" que están sujetos a todo tipo de reglas extrañas de orden de inicialización y cosas. Tendemos a no utilizarlos en C++ idiomático tanto como podamos ayudarlo.

En cuanto a las variables específicas en el ejemplo del código, todos los comentarios son precisos, a pesar del error en la terminología.

Adición:

Los términos "montón" y "pila" están obsoletos, en relación con espalda cuando las bibliotecas de ejecución más populares utilizan estas estructuras de datos para almacenar objetos que eran de forma dinámica y automáticamente asignado-, respectivamente (los objetos asignados estáticamente no encajan en ninguna categoría, por cierto).

En la actualidad, esto no siempre es cierto, y ciertamente no es un requisito del estándar C++, que no se preocupa de dónde se almacenan las cosas. Solo le importa cómo se crean y destruyen, y cuánto tiempo viven.

+1

En realidad, tenga en cuenta que los miembros de clase con duración automática pueden no estar en la pila física "(si tal cosa existe), si la clase encapsulante fue asignada en el" montón "(si tal cosa existe). Otro buen ejemplo de por qué no deberías usar estos términos. –

+1

Creo que n y pubVar se almacenan en el montón, como parte del objeto contenedor. – Ariel

+1

@Ariel: si la implementación usa un montón, entonces sí, en este caso, los miembros estarán en ese "montón" porque el objeto sí lo está. C++ no tiene conocimiento de eso, sin embargo. –

5

He actualizado sus anotaciones con lo que creo que es más correcto. Tenga en cuenta que Tomalak está en lo cierto al decir que 'stack' y 'heap' no están especificados por el estándar, y que se pueden usar mecanismos distintos de un stack para pasar parámetros a las variables automáticas.

Sin embargo, sigo usando esos términos porque en realidad se usan con bastante frecuencia en implementaciones de compiladores, los términos son más o menos bien entendidos (o fáciles de entender), y creo que aún ilustran pragmáticamente lo que le interesa en saber

class Foobar 
{ 
     int n; //Stored wherever the current object is stored 
      // (might be static memory, stack or heap depending 
      // on how the object is allocated) 

     public: 

      int pubVar; //Stored wherever the current object is stored 
         // (might be static memory, stack or heap depending 
         // on how the object is allocated) 

      void foo(int param) //param stored in stack or register 
      { 
       int *pp = new int; //int is allocated on heap. 
       n = param; 
       static int nStat; //Stored in static area of memory 
       int nLoc;   //stored in stack or register 
       string str = "mystring"; // `str` is stored in stack, however 
             // the string object may also use heap 
             // to manage its data 
       .. 
       if(CONDITION) 
       { 
        static int nSIf; //stored in static area of memory 
        int loopvar;  //stored in stack or register 
        .. 
       } 
      } 
} 

int main(int) 
{ 
    Foobar bar; //bar stored in stack 

    Foobar *pBar; //pBar is stored in stack 

    pBar = new Foobar(); //the object is created in heap. 
          // The non-static data members are stored in that 
          // memory block. 

} 
+1

Desafortunadamente son ambiguos y confusos. Puede ser que "la mayoría de la gente" los use de esta manera, pero eso no es un argumento para evitar la ambigüedad. "La mayoría de la gente" piensa que Sydney es la capital de Australia; eso de ninguna manera lo hace correcto. –

+0

+1 Una gran explicación detallada y metódica. – templatetypedef

+0

@Micheal "dependiendo de cómo se asigna el objeto" no es claro para mí. ¿Te refieres a la siguiente distinción: barra de Foobar; (// aquí el objeto se asigna en la pila) Foobar * pBar = new Foobar(); (// aquí el objeto se asigna en el montón) – blitzkriegz

1

Estoy de acuerdo con Tomalak,

C++ no le importa donde las cosas se almacenan .Solo le importa cómo se construyen y destruyen , y sobre cuánto tiempo viven.

Como sucede, si se define la implementación, el compilador podría optimizar de tal manera que no tenga nada almacenado en la "pila" cuando lo espere. La forma en que ocurre la asignación en el montón se define mediante la implementación de una función nueva/malloc o de un tercero (los nuevos pueden llamar a malloc).

Lo más probable es que va a pasar en su ejemplo, es la siguiente:

Foobar bar; // bar will *most likely* be allocated on the "stack". 
Foobar *pBar; // pBar will *most likely* be allocated on the "stack". 
pBar = new Foobar(); // pBar will stay as is, and point to the location on the "heap" where your memory is allocated by new. 

Algunas cosas que puede que se pregunte acerca. Una matriz estilo C, como int array[5] no se almacena de la misma manera que int* pointer= new int[5], el segundo caso muy probablemente use más memoria, ya que almacena no solo la memoria de la matriz, sino también la memoria en la "pila" para el puntero .

Las constantes estáticas como 5 y "cake" se almacenan generalmente en una sección .DATA separada del ejecutable.

Lo importante a tener en cuenta cuando se usa C++, la mayoría de estas cosas están definidas por la implementación.

+0

Como dices * muy probablemente *, ¿puede la asignación de/* barra de Foobar; */sucede en el montón? – blitzkriegz

+1

+1 por estar principalmente en lo cierto. –

+1

@Mahatma: Absolutamente. Depende de donde lo escribas! Por cierto, los backticks de SO pueden delimitar muestras de código y formatearlas por usted. –

0

Los miembros de datos no estáticos están "dentro" de cada instancia de esa clase: si eso está en la pila o en el montón, o en otro lugar, se desconoce con solo mirar al miembro en la definición de clase. No tiene sentido hablar sobre el almacenamiento de miembros de datos no estáticos sin hablar sobre el almacenamiento de la instancia de la clase a la que pertenecen.

struct A { 
    int n; // you cannot say n is always on the stack, or always on the heap, etc. 
}; 

int main() { 
    A a; // a is on the stack, so a.n is also on the stack 
    A *p = new A(); // *p, which means the object pointed to by p, is on the heap, 
        // so p->n is also on the heap 
        // p itself is on the stack, just like a 
    return 0; 
} 

A global; // global is neither on the stack nor on the heap, so neither is global.n 

"La pila" es donde van variables a la vida útil de una invocación de función única; esto también se llama "duración de almacenamiento automático". Hay varias estrategias de asignación de pila y, en particular, cada subproceso tiene su propia pila, aunque la "pila" debe estar clara desde el contexto. Hay cosas interesantes que suceden con las pilas divididas (que permiten crecer y contraerse), pero en ese caso, todavía hay una pila dividida en varias piezas.

"The heap" es solo un nombre inapropiado en el sentido de que "the" se refiere al montón "principal", como lo usan malloc y varias formas de new; esto también se llama "duración de almacenamiento dinámico".

Las variables globales, los miembros de datos estáticos y las estáticas a nivel de función no pertenecen a la pila ni al montón; también llamado "duración de almacenamiento estático".

Cuestiones relacionadas