38 votos

Puede una clase de C++ determinar si está en la pila o montón?

Tengo

class Foo {
....
}

Hay una manera para que los Foo a ser capaz de separar:

function blah() {
  Foo foo; // on the stack
}

y

function blah() {
  Foo foo* = new Foo(); // on the heap
}

Quiero Foo ser capaz de hacer cosas diferentes dependiendo de si se encuentran en la Pila o Montón.

Editar:

Alof de personas me han preguntado "¿por qué hacen esto?"

La respuesta:

Estoy usando un ref contados GC ahora. Sin embargo, quiero tener capacidad para ejecutar marca y de barrido. Para esto, necesito a la etiqueta de un conjunto de "raíz" punteros -- estos son los punteros en la pila. Por lo tanto, para cada clase, me gustaría saber si están en la pila o en el montón.

18voto

sth Puntos 91594

Un hacky manera de hacerlo:

struct Detect {
   Detect() {
      int i;
      check(&i);
   }

private:
   void check(int *i) {
      int j;
      if ((i < &j) == ((void*)this < (void*)&j))
         std::cout << "Stack" << std::endl;
      else
         std::cout << "Heap" << std::endl;
   }
};

Si el objeto se crea en la pila debe vivir en algún lugar en la dirección de la parte exterior de las funciones de la pila de variables. El montón normalmente crece desde el otro lado, por lo que la pila y el montón iba a reunirse en algún lugar en el medio.

(Hay seguro sistemas en los que esto no iba a funcionar)

10voto

paxdiablo Puntos 341644

Usted necesita realmente nos pide la pregunta real :-) Es evidente por qué crees que esto es necesario, pero es casi seguro que no es. De hecho, es casi siempre una mala idea.

¿Por qué usted piensa que usted necesita para hacer esto?

Generalmente, me parece que es porque los desarrolladores desea eliminar o no eliminar el objeto, en función de donde fue asignado, pero eso es algo que por lo general se deben a la izquierda para el cliente de su código en lugar de su propio código.


Actualización:

Disculpas, usted probablemente ha encontrado uno de los pocos ámbitos en los que lo que estás haciendo tiene sentido. Idealmente, sería anular todas la asignación de la memoria y de la asignación a los operadores a mantener un seguimiento de lo que se crea y se elimina de la pila.

Sin embargo, no estoy seguro de que es una simple cuestión de interceptar el nuevo/eliminar de la clase ya que puede haber situaciones donde delete no es llamado y, puesto que la marca de barrido se basa en un recuento de referencia, usted necesita ser capaz de interceptar puntero asignaciones para que funcione correctamente.

¿Has pensado en cómo vas a manejar eso?

El ejemplo clásico:

myobject *x = new xclass();
x = 0;

no dará como resultado una eliminación de la llamada.

También, ¿cómo va a detectar el hecho de que el puntero a uno de sus instancias en la pila? La intercepción de new y delete puede dejar de almacenar si el objeto en sí es la pila o montón pero estoy en una pérdida en cuanto a cómo usted diga donde el puntero se va a asignar, en especial con un código como:

myobject *x1 = new xclass();  // yes, calls new.
myobject *x2 = x;             // no, it doesn't.

8voto

Terry Mahaffey Puntos 7368

La respuesta es no, no hay ningún estándar/portátil manera de hacer esto. Hacks que implican una sobrecarga el operador new tienden a tener agujeros. Hacks que dependen de la comprobación de las direcciones de los punteros son específicos del sistema operativo y el montón de aplicación específica, y puede cambiar en futuras versiones del sistema operativo. Usted puede estar cómodo con eso, pero yo no construir cualquier tipo de sistema en torno a este comportamiento.

Me gustaría empezar a buscar diferentes maneras para lograr su objetivo - tal vez usted puede tener un tipo totalmente distinto a servir como el "root" en su esquema, o solicitar a los usuarios que (correctamente) anotar la pila asignada tipos como tal, con un especial constructor.

4voto

Matt Joiner Puntos 29194

De una manera más directa, y menos intrusiva método sería buscar el puntero en la región de memoria los mapas (como /proc/<pid>/maps). Cada hilo tiene una región asignada a su pila. Las variables estáticas y globales vivir en el .bss sección, constantes en un rodata o const segmento, y así sucesivamente.

3voto

Michael Koval Puntos 3597

No estoy seguro de lo que usted está pidiendo, pero la invalidación de la new operador puede ser lo que usted está tratando de hacer. Como la única manera segura de crear un objeto en la pila en C++ es el uso de la new operador, se puede diferenciar entre los objetos que existen en el montón, en comparación con otras formas de la memoria. Google "sobrecarga de nuevo en c++" para obtener más información.

Usted debe, sin embargo, consideran que si la diferenciación entre los dos tipos de memoria es realmente necesario desde el interior de la clase. Tener un objeto se comportan de forma diferente dependiendo de donde se almacena suena como una receta para el desastre si usted no es cuidadoso!

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X