Allouer statiquement la mémoire des objets; l'initialiser dynamiquement?

9

J'ai un objet dont le constructeur reçoit un paramètre. Si je connais la valeur du paramètre au moment de la compilation, je peux construire l'objet statiquement:

static FOOOBJ foo(3);

(Je comprends que ce n'est pas vraiment fait statiquement, c'est-à-dire par le compilateur, mais cela se fait en fait pendant l'installation).

Mais si je ne connais pas la valeur du paramètre au moment de la compilation, je voudrais quand même pré-allouer de l'espace pour l'objet mais construire l'objet dans cet espace au moment de l'exécution. Peut-il être fait sans .initialize()méthode séparée ?

JRobert
la source

Réponses:

3

L'utilisation d'une initialize()méthode pour une classe est contraire au principe d'un constructeur de classe, c'est-à-dire qu'une fois qu'une instance de classe a été construite , elle doit être " prête à l'emploi ".

Comme suggéré par la réponse d'Ignacio, la syntaxe de placement C ++ est bien meilleure pour votre objectif.

Cependant, avec les bibliothèques Arduino, la syntaxe de placement n'est pas prise en charge "prête à l'emploi", vous devez donc l'implémenter vous-même; n'ayez pas peur, c'est assez simple:

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

La syntaxe de placement peut être une bête complexe en C ++, mais pour votre usage spécifique, son utilisation peut être assez simple:

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

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

La différence avec votre code actuel est qu'il foos'agit désormais d'un pointeur, donc tout appel de méthode utilisera à la ->place de ..

Si vous voulez absolument continuer à utiliser foocomme instance et non comme pointeur, vous pouvez le faire (mais je ne le conseille pas comme expliqué plus loin) en utilisant une référence à la place:

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

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

Le problème avec ce code, c'est que vous ne pouvez pas savoir s'il fooa déjà été construit avec une FOOOBJinstance réelle ou non; à l'aide d'un pointeur, vous pouvez toujours vérifier si c'est le cas 0ou non.

En utilisant la syntaxe de placement, vous devez savoir que vous ne pouvez pas deletel' fooinstance ci-dessus. Si vous voulez détruire foo(c'est-à-dire vous assurer que son destructeur est appelé), vous devez alors appeler explicitement le destructeur:

foo->~FOOOBJ();
jfpoilpret
la source
1
Je n'étais pas au courant de la syntaxe mais cela a un sens total! Le constructeur doit-il en être conscient / conçu pour lui? FOOOBJest un objet OneWire, utilisant la bibliothèque de Jim Studt (v2.2). Je reçois le message error: no matching function for call to 'operator new(unsigned int, byte [14])'sur l' newappel. Il semble que avr-g ++ ne comprenne pas la syntaxe.
JRobert
Oui, vous avez raison, j'utilise Eclipse pour mes projets Arduino et ce que j'ai vérifié, cela semblait fonctionner, sauf que ce qui fonctionnait était la compilation Eclipse C ++, pas avr-g ++! J'ai modifié ma réponse pour afficher une solution de contournement simple.
jfpoilpret
Concernant votre question sur le constructeur, il n'y a pas d'exigence spécifique, mais si le constructeur lui-même effectue l'allocation dynamique, alors le placement nouveau ne l'empêchera pas.
jfpoilpret
J'utilise également Eclipse - avec quel compilateur C ++ le vôtre est-il configuré? De plus, en regardant le constructeur OneWire, il ne fait newrien, il initialise simplement quelques E / S.
JRobert
J'utilise Eclipse avec le plugin eclipse.baeyens.it (qui utilise les outils Arduino IDE, c'est-à-dire avr-g ++ + Arduino libs); mais la compilation C ++ se produit à la volée avec Eclipse C ++, et utilise avr-g ++ uniquement lors du lancement de la construction Arduino. Je n'avais pas vérifié la dernière étape au départ.
jfpoilpret
4

Vous pouvez utiliser la syntaxe de placement pour spécifier une allocation existante dans laquelle instancier la classe.

FOOOBJ foo(0);

 ...

  FOOOBJ *f = new (foo) FOOOBJ(3);
Ignacio Vazquez-Abrams
la source
Je suggère de remplacer la déclaration de foopar char foo[sizeof FOOOBJ];afin que le FOOOBJconstructeur ne soit pas appelé, fooce qui pourrait être un vrai problème selon ce que fait le constructeur.
jfpoilpret