2010-10-23 17 views
6

Estoy aprendiendo D, y estoy confundido por un error que estoy recibiendo.Creación de instancias de objetos basados ​​en pila en D

considerar lo siguiente:

module helloworld; 

import std.stdio; 
import std.perf; 

ptrdiff_t main(string[] args) 
{ 
    auto t = new PerformanceCounter; //From managed heap 
    //PerformanceCounter t;    //On the stack 

    t.start(); 
    writeln("Hello, ", size_t.sizeof * 8, "-bit world!"); 
    t.stop(); 

    writeln("Elapsed time: ", t.microseconds, " \xb5s."); 

    return 0; 
} //main() 

produce una perfectamente respetable:

Hello, 32-bit world! 
Elapsed time: 218 µs. 

Ahora considere lo que sucede cuando intento inicializar PerformanceCounter en la pila en lugar de utilizar el montón administrado:

//auto t = new PerformanceCounter; //From managed heap 
PerformanceCounter t;    //On the stack 

Rendimientos:

--- killed by signal 10 

Estoy perplejo. ¿Alguna idea de por qué se rompe esto? (DMD 2.049 en Mac OS X 10.6.4). Gracias de antemano por ayudar a n00b.

Respuesta

5

Parece que está mezclando clases de C++ con clases D.

clases D son siempre pasada por referencia (a diferencia, por ejemplo, clases de C++), y PerformanceCounter t no asignar la clase en la pila, simplemente un puntero a ella.

Esto significa que t se establece en null porque, bueno, null es el inicializador predeterminado para los punteros, de ahí el error.

EDIT: Se puede pensar en la clase D Foo como C++ 's Foo*.

Si desea que esto se asigne en el montón, podría intentar usar structs en su lugar, también pueden tener métodos, al igual que las clases. Sin embargo, no tienen herencia.

+0

¡Gracias por la pista! :) (Eso tiene sentido y también responde por qué no se requiere la desreferencia/operador miembro del objeto (->) – anoncow

+0

Bueno, el operador -> no sería necesario de todos modos, por ejemplo, en C, el compilador (si es inteligente) suficiente) realmente puede advertirle que está utilizando el operador incorrecto. De manera similar, los indicadores de D's (por ejemplo, Foo *) no necesitan ->, pero funcionan con el punto: 'Foo * foo = ; foo.bar = 5; ' –

+0

Lo siento, me refiero a que no lo necesita para el objeto dinámicamente asignado, no el basado en la pila. – anoncow

1

Gracias, Tim.

Gracias a su respuesta, yo era capaz de encontrar lo siguiente en http://www.digitalmars.com/d/2.0/memory.html:


instancias Asignación de clase en la pila

instancias de clases normalmente se asignan en el montón de basura recogida. Sin embargo, si ellos: se asignan como símbolos locales en una función se asignan utilizando el nuevo use new sin argumentos (los argumentos del constructor están permitidos) tienen la clase de almacenamiento de alcance y luego se asignan en la pila. Esto es más eficiente que hacer un ciclo asignar/libre en la instancia. Pero tenga cuidado de que cualquier referencia al objeto no sobreviva al regreso de la función.

class C { ... } 

scope c = new C(); // c is allocated on the stack 
scope c2 = new C(5); // allocated on stack 
scope c3 = new(5) C(); // allocated by a custom allocator 

Si la clase tiene un destructor, destructor entonces que se garantiza que se ejecute cuando el objeto de clase se sale del ámbito, incluso si el alcance se sale a través de una excepción.


Mi código lee ahora

scope t = new PerformanceCounter(); //On the stack 

Este (supuestamente) asigna en la pila y funciona muy bien. :)

¡Gracias otra vez!

+2

Como señala dsimcha en su publicación, sin embargo, el alcance está programado para obsoleto, por lo que no es una buena solución a largo plazo. –

3

La respuesta más obvia es usar un struct. Si está utilizando una biblioteca que no tiene control o algo así y las asignaciones de montón son un problema de rendimiento, puede usar la funcionalidad std.typecons.scoped para asignar de forma insegura una instancia de clase en la pila. La instancia aún se pasa por referencia y si su vida útil excede la duración del marco de pila actual, se producirá un comportamiento no definido. La palabra clave scope según la respuesta de ancow va a funcionar, pero está programada para desactivarse en D2.

+0

¡Oh, no! ¡También me enamoré del alcance! Estoy usando D2, así que iré a leer sobre por qué, esto ha sido obsoleto, por desgracia. Gracias por la sugerencia de estructura: el mecanismo de asignación de pila de C++ también sufre el mismo problema. – anoncow

+0

Creo que ha quedado obsoleto esencialmente porque no es seguro. Tener una clase en la pila corre el riesgo de mantener una referencia en ella después de que la función regrese y tener esa referencia ya no sea válida. Si está en el montón, no será basura recolectada hasta que todas las referencias hayan desaparecido, entonces no tendrás ese problema. –

+0

@anoncow: IIRC, ** scope ** se reemplaza por solución de biblioteca. Smth like ** Scoped! (YourType) var ** –