Objektspeicher statisch zuordnen; dynamisch initialisieren?


9

Ich habe ein Objekt, dessen Konstruktor einen Parameter übergeben bekommt. Wenn ich den Parameterwert zur Kompilierungszeit kenne, kann ich das Objekt statisch erstellen:

static FOOOBJ foo(3);

(Ich verstehe, dass es nicht wirklich statisch gemacht wird, dh vom Compiler, sondern tatsächlich während des Setups).

Wenn ich den Parameterwert zur Kompilierungszeit nicht kenne, möchte ich dem Objekt dennoch vorab Speicherplatz zuweisen, aber das Objekt zur Laufzeit in diesem Bereich erstellen. Kann es ohne eine separate .initialize()Methode gemacht werden?

Antworten:


3

Unter Verwendung einer initialize()Methode zu einer Klasse steht im Widerspruch zu dem Prinzip eines Klassenkonstruktors, dh sobald eine Klasseninstanz wurde konstruiert , sollte es „sein einsatzbereit “.

Wie in Ignacios Antwort vorgeschlagen, ist die C ++ - Platzierungssyntax für Ihren Zweck viel besser.

Bei Arduino-Bibliotheken wird die Platzierungssyntax jedoch nicht "out of the box" unterstützt, sodass Sie sie selbst implementieren müssen. Keine Angst, das ist ganz einfach:

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

Die Platzierungssyntax kann in C ++ ein komplexes Problem sein, aber für Ihren speziellen Zweck kann ihre Verwendung recht einfach sein:

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

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

Der Unterschied zu Ihrem aktuellen Code besteht darin, dass er foojetzt ein Zeiger ist. Daher wird jeder Methodenaufruf ->anstelle von verwendet ..

Wenn Sie unbedingt weiterhin fooals Instanz und nicht als Zeiger verwenden möchten, können Sie dies tun (ich rate jedoch nicht dazu, wie später erläutert), indem Sie stattdessen eine Referenz verwenden:

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

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

Das Problem mit diesem Code ist, dass Sie nicht wissen können, ob foobereits eine reale FOOOBJInstanz erstellt wurde oder nicht. Mit einem Zeiger können Sie jederzeit überprüfen, ob dies der Fall ist 0oder nicht.

Bei Verwendung der Platzierungssyntax müssen Sie sich bewusst sein, dass Sie deletedie fooobige Instanz nicht verwenden können . Wenn Sie zerstören möchten foo(dh sicherstellen möchten, dass sein Destruktor aufgerufen wird), müssen Sie den Destruktor explizit aufrufen:

foo->~FOOOBJ();

1
Die Syntax war mir nicht bekannt, aber das macht total Sinn! Muss der Konstruktor sich dessen bewusst sein / dafür ausgelegt sein? FOOOBJist ein OneWire-Objekt, das die Bibliothek von Jim Studt (v2.2) verwendet. Ich erhalte die Nachricht error: no matching function for call to 'operator new(unsigned int, byte [14])'beim newAnruf. Es sieht so aus, als ob avr-g ++ die Syntax möglicherweise nicht versteht.
JRobert

Ja, Sie haben Recht, ich verwende Eclipse für meine Arduino-Projekte und was ich überprüft habe, schien zu funktionieren, außer dass die Eclipse C ++ - Kompilierung funktioniert hat, nicht avr-g ++! Ich habe meine Antwort bearbeitet, um eine einfache Problemumgehung anzuzeigen.
Jfpoilpret

In Bezug auf Ihre Frage zum Konstruktor gibt es keine spezielle Anforderung. Wenn der Konstruktor selbst eine dynamische Zuordnung durchführt, wird dies durch die Platzierung durch eine neue nicht verhindert.
jfpoilpret

Ich verwende auch Eclipse - mit welchem ​​C ++ - Compiler ist Ihr konfiguriert? Wenn man sich den OneWire-Konstruktor ansieht, tut er newnichts, er initialisiert nur einige E / A.
JRobert

Ich verwende Eclipse mit dem Plugin eclipse.baeyens.it (das Arduino IDE-Tools verwendet, dh avr-g ++ + Arduino libs). Die C ++ - Kompilierung erfolgt jedoch im laufenden Betrieb mit Eclipse C ++ und verwendet avr-g ++ nur beim Starten des Arduino-Builds. Ich hatte den letzten Schritt zunächst nicht überprüft.
jfpoilpret

4

Mithilfe der Platzierungssyntax können Sie eine vorhandene Zuordnung angeben, in der die Klasse instanziiert werden soll.

FOOOBJ foo(0);

 ...

  FOOOBJ *f = new (foo) FOOOBJ(3);

Ich würde vorschlagen, die Deklaration von foodurch zu ersetzen, char foo[sizeof FOOOBJ];damit der FOOOBJKonstruktor nicht aufgerufen wird. fooDies könnte ein echtes Problem sein, je nachdem, was der Konstruktor tut.
jfpoilpret
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.