2016-03-31 3 views
0

Diese Frage besteht im Wesentlichen aus zwei Teilen: Speichern von Konfigurationswerten in einer einzigen Datei/Stelle und Verzögern der Initialisierung eines enthaltenen Objekts.Gesamtkonfigurationsobjekt für ein Gott-Objekt und späte Initialisierung

Speicher von Konfigurationswerten

Ich habe ein eingebettetes Programm, das eine Leiterplattentestvorrichtung für einen halbautomatischen Test steuert. Ich möchte alle Grenzwerte/Testparameter an einem einzigen Ort speichern (vorzugsweise als Read-Only/Konstanten), damit sie in der Zukunft einfach gefunden und optimiert werden können. Das Problem ist, dass einige der Werte in verschachtelten Strukturen liegen und die einzige Möglichkeit, diese Objekte zu initialisieren, ist die gefürchtete Initialisierungsliste, in der die Rückverfolgbarkeit verloren geht (oder ein Konstruktor, der fast genauso schlecht ist).

z.B.

class Configuration { 

public: 
    struct NestedStruct { 
    float value1; 
    float value2; 
    float value3; 
    }; 

    struct ContainerStruct { 
    int value1; 
    float value2; 
    NestedStruct nested1; 
    NestedStruct nested2; 
    NestedStruct nested3; 
    float value3; 
    }; 

    // Initialise struct data member. 
    // Not obvious which value is which? 
    constexpr static const ContainerStruct containerStruct {5, 2.3, 1.4, 4.2, 0.7, 3.5, 2.5, 3.5, 0.2, 0.2, 0.1, 4.6}; 

    // Slightly more readable 
    constexpr static const ContainerStruct containerStruct {5, 2.3, {1.4, 4.2, 0.7}, {3.5, 2.5, 3.5}, {0.2, 0.2, 0.1}, 4.6}; 

}; 

Wie können wir lesen speichern nur Konfigurationswerte aus den komplexen/verschachtelter Struktur Werte an einem Ort, während der Lesbarkeit beibehalten?

Controller/god Objekt Initialisierung

Ich habe beschlossen, die Kernfunktionalität in einem einzigen Controller-Objekt zu wickeln, das mehrere Objekte enthalten instanziiert. Eines dieser Objekte wird über einen Zeiger an einige der anderen Objekte übergeben. Ich verwende die oben genannten Konfigurationswerte (für die es viele gibt!), Um diese Objekte zu initialisieren.

Die Verwendung einer Initialisierungsliste macht den Konstruktor der Controller-Klasse lang und unordentlich. Eine Möglichkeit, dies zu umgehen, besteht darin, einen leeren Konstruktor für die enthaltenen Objekte mit einer separaten Initialisierungsfunktion zu erstellen, die ich im Rumpf des Konstruktors der Steuerung aufrufen könnte.

Allerdings habe ich immer gelesen, dass zwei Schritt/Lazy-Initialisierung ist schlecht, da das Objekt nicht sofort verwendbar ist. Gibt es einen anderen Weg?

Vielleicht gibt es einen besseren Weg, als es in ein Gott-Objekt zu wickeln?

Beispiel Parameter, die ich an einem Ort gespeichert werden sollen:

Adc Objektparameter:

float voltageReference; 
uint8_t slaveSelectPin; 

Navigationobjektparameter:

struct AdcValues { 
    uint_fast16_t buttonUp; 
    uint_fast16_t buttonDown; 
    uint_fast16_t buttonLeft; 
    uint_fast16_t buttonRight; 
    uint_fast16_t buttonCentre; 
    uint_fast8_t tolerance; 
}; 

UutPower Objektparameter:

struct CurrentCompensation { 
    float LowX; 
    float LowC; 
    float MidX; 
    float MidC; 
    float HighX; 
    float HighC; 
}; 

VoltageTests Objektparameter:

struct TestParameter { 
    float scalingFactor; // Potential divider scaling for voltages >voltageRef. 
    float limitLower; 
    float limitUpper; 
    const char *signalName; 
}; 

// Lots of nested structs. 
struct TestParameters { 
    TestParameter tb1_1; 
    TestParameter tp15; 
    TestParameter tp4; 
    TestParameter tp1; 
    TestParameter tp3; 
    TestParameter tp20; 
    TestParameter tp12; 
    TestParameter tp29; 
    TestParameter tp28; 
    TestParameter con3_6; 
    TestParameter con3_2; 
} 

Weitere Parameter:

float currentLimitLow; 
float currentLimitHigh; 
const char *version; 

Jede Hilfe sehr geschätzt.

+0

Ist C eine Option? In C könnten Sie designierte Initialisierer verwenden 'constexpr static const ContainerStruct containerStruct = {.value1 = 5}'. – Lundin

+0

Es verwendet einen Arduino mit eingeschränkter Funktionalität von C++ - Standardbibliotheken (C mit Klassen, die ich vermute). Leider akzeptiert der Compiler das nicht, auch nicht den anderen Standard mit einem Doppelpunkt 'containerStruct = {value1: 5}' –

+0

Ich hatte einmal eine sehr ähnliche Situation in einem Projekt. Eingebettete sys/Mikrocontroller, riesige Menge an Daten in Flash Eeprom (64kb), alles in einer großen Monster-Struktur. Es ist immer noch ziemlich gut geworden, weil ich bestimmte Initialisierer verwenden konnte. Ohne sie wäre es ziemlich hässlich geworden. Eine der wenigen Anwendungen, die ich für designierte Initialisierer gefunden habe. – Lundin

Antwort

0

Die wahrscheinlichste Option ist wahrscheinlich Ihre Strukturen in einzelne const Variablen zu teilen, müssen Sie sie durch Variablennamen oder etwas stattdessen gruppieren.

Sobald Sie dies haben, ändern Sie Ihre Linker-Datei, um jeder einzelnen Variablen eine dedizierte Adresse zu geben. Oder alternativ könnte Ihr Compiler eine nicht-standardmäßige Erweiterung dafür haben, wie der @ Operator.

Damit können Sie jede einzelne Variable einzeln initialisieren.

Dies ist ideal für die Wartung, da das Hinzufügen oder Entfernen von Variablen die Adressen anderer, nicht verwandter Variablen nicht ändert. Planen Sie Ihre Memory Map mit größter Sorgfalt und lassen Sie hier und da "Löcher", um zukünftige Erweiterungen zu ermöglichen. Berücksichtigen Sie ggf. die Ausrichtung (wenn Sie eine 8-Bit-MCU verwenden, ist dies kein Problem).

Ein weiterer Vorteil davon ist, dass Sie const Variablen zu den Dateien lokalisieren können, wo sie verwendet werden, anstatt sie in einer globalen "Monster-Struktur" zu halten.

+0

Würden Sie mich auf weitere Informationen zum @ -Operator hinweisen können (Google mag das @ oder at nicht). Ich habe noch keine Änderungen an Linker-Dateien vorgenommen (ich habe erst mit dem Lernen von C++ angefangen und seit Januar alles, was mit Embedded zusammenhängt) und keine anderen Erfahrungen mit dem Build-Prozess auf niedrigerer Ebene gemacht. Dies ist ein 8-Bit 'crappy' AVR Mega. Ich muss vielleicht akzeptieren, dass es keine super elegante Möglichkeit gibt, dies zu tun. Danke für die Ideen. –

+0

@ mattb5906 Sie müssen das Handbuch Ihres Compilers lesen, um zu sehen, wie Objekte an einer bestimmten Adresse zugewiesen werden. – Lundin