Asignar memoria de objeto estáticamente; ¿Inicializarlo dinámicamente?

9

Tengo un objeto cuyo constructor pasa un parámetro. Si conozco el valor del parámetro en tiempo de compilación, puedo construir el objeto estáticamente:

static FOOOBJ foo(3);

(Entiendo que en realidad no se hace estáticamente, es decir, por el compilador, sino que realmente se hace durante la configuración).

Pero si no conozco el valor del parámetro en tiempo de compilación, todavía me gustaría asignar previamente espacio para el objeto pero construir el objeto en ese espacio en tiempo de ejecución. ¿Se puede hacer sin un .initialize()método separado ?

JRobert
fuente

Respuestas:

3

El uso de un initialize()método para una clase es contrario al principio de un constructor de clases, es decir, una vez que se ha construido una instancia de clase , debe estar " lista para usar ".

Como sugiere la respuesta de Ignacio, la sintaxis de ubicación de C ++ es mucho mejor para su propósito.

Sin embargo, con las bibliotecas Arduino, la sintaxis de ubicación no es compatible "de fábrica", por lo que debe implementarla usted mismo; no temas, eso es bastante sencillo:

void* operator new(size_t size, void* ptr)
{
    return ptr;
}

La sintaxis de ubicación puede ser una bestia compleja en C ++, pero para su propósito específico, su uso puede ser bastante simple:

static char buffer[sizeof FOOOBJ];
static FOOOBJ* foo;

void setup() {
    ...
    foo = new (buffer) FOOOBJ(3);
    ...
}

La diferencia con su código actual es que fooahora es un puntero, por lo tanto, se usará cualquier llamada de método en ->lugar de ..

Si absolutamente quiere seguir usándolo foocomo una instancia y no como un puntero, puede hacerlo (pero no lo aconsejo como se explica más adelante) utilizando una referencia en su lugar:

static char buffer[sizeof FOOOBJ];
static FOOOBJ& foo = *((FOOOBJ*) buffer);

void setup() {
    ...
    new (buffer) FOOOBJ(3);
    ...
}

El problema con este código es que no puede saber si fooya se ha construido con una FOOOBJinstancia real o no; Con un puntero, siempre puede comprobar si es 0o no.

Al utilizar la sintaxis de ubicación, debe tener en cuenta que no puede deletela fooinstancia anterior. Si desea destruir foo(es decir, asegurarse de que se llama a su destructor), debe llamar explícitamente al destructor:

foo->~FOOOBJ();
jfpoilpret
fuente
1
No estaba al tanto de la sintaxis, ¡pero eso tiene mucho sentido! ¿El constructor debe estar al tanto / diseñado para ello? FOOOBJes un objeto OneWire, que usa la biblioteca de Jim Studt (v2.2). Recibo el mensaje error: no matching function for call to 'operator new(unsigned int, byte [14])'de la newllamada. Parece que avr-g ++ puede no entender la sintaxis.
JRobert
Sí, tienes razón, estoy usando Eclipse para mis proyectos de Arduino y lo que verifiqué, parecía funcionar, ¡excepto que lo que funcionó fue la compilación de Eclipse C ++, no avr-g ++! He editado mi respuesta para mostrar una solución simple.
jfpoilpret
Con respecto a su pregunta sobre el constructor, no hay un requisito específico, pero si el propio constructor realiza una asignación dinámica, la colocación nueva no lo impedirá.
jfpoilpret
También estoy usando Eclipse: ¿con qué compilador de C ++ está configurado el suyo? Además de mirar el constructor OneWire, no hace newnada, solo inicializa algunas E / S.
JRobert
Estoy usando Eclipse con el complemento eclipse.baeyens.it (que usa las herramientas Arduino IDE, es decir, avr-g ++ + Arduino libs); pero la compilación de C ++ ocurre sobre la marcha con Eclipse C ++, y usa avr-g ++ solo cuando se inicia la compilación Arduino. No había verificado el último paso inicialmente.
jfpoilpret
4

Puede usar la sintaxis de ubicación para especificar una asignación existente en la que instanciar la clase.

FOOOBJ foo(0);

 ...

  FOOOBJ *f = new (foo) FOOOBJ(3);
Ignacio Vazquez-Abrams
fuente
Sugeriría reemplazar la declaración de foocon char foo[sizeof FOOOBJ];para que FOOOBJno se llame al constructor, lo fooque podría ser un problema real dependiendo de lo que haga el constructor.
jfpoilpret