Wie vermeidet man C ++ Code Bloat, der von Template Instanziierung und Symboltabelle ausgegeben wird?

8

Ich habe vor einigen Jahren ein Bare-Metal-Projekt (Cortex-M) gestartet. Bei der Projekteinrichtung haben wir uns entschieden, gcc toolchain mit C ++ 11 / C ++ 14 usw. zu verwenden und sogar C ++ - Ausnahmen und rtti zu verwenden.

Wir verwenden derzeit gcc 4.9 von launchpad.net/gcc-arm-embedded (mit einem Problem, das uns derzeit daran hindert, auf eine neuere gcc-Version zu aktualisieren).

Zum Beispiel hatte ich eine Basisklasse und eine abgeleitete Klasse wie diese geschrieben (siehe auch das Beispiel hier ):

%Vor%

Damit können die Kunden meiner Klasse jetzt z. B .:

verwenden %Vor%

Nun möchte ich die Verwendung der Klasse ein wenig komfortabler machen und habe die folgende Vorlage eingeführt:

%Vor%

Und ab jetzt können meine Kunden schreiben:

%Vor%

Aber von jetzt an hatte ich eine zunehmende Größe meiner ausführbaren Binärdatei beobachtet. Es scheint, dass gcc Symbolinformationen für jede andere Template-Instanziierung von FixedMemoryStreamWithBuffer hinzugefügt hat (weil wir aus irgendeinem Grund rtti verwenden).

Könnte es eine Möglichkeit geben, Symbolinformationen nur für bestimmte Klassen / Vorlagen / Template-Instanziierungen loszuwerden?

Es ist in Ordnung, eine nicht portable gcc-only-Lösung dafür zu bekommen.

Aus irgendeinem Grund haben wir uns entschieden, Vorlagen anstelle von Präprozessor-Makros zu bevorzugen. Ich möchte eine Präprozessor-Lösung vermeiden.

    
Joe 19.12.2017, 19:04
quelle

2 Antworten

2

Ja, es gibt eine Möglichkeit, die notwendigen Symbole fast bis auf 0 zu bringen: mit der Standardbibliothek. Ihre OutStream -Klasse ist eine vereinfachte Version von std::basic_ostream . Dein OutStream::write ist wirklich nur std::basic_ostream::write und so weiter. Sehen Sie sich hier an. Der Überlauf wird sehr genau gehandhabt, obwohl der Vollständigkeit halber auch auf underflow eingegangen wird, d. H. Auf die Notwendigkeit des Datenabrufs; Sie können es als undefined lassen (es ist auch virtual ).

Ähnlich ist Ihr FixedMemoryStream std::basic_streambuf<T> mit einer festen Größe (a std::array<T> ) get / put Bereich.

Also, lassen Sie Ihre Klassen einfach von den Standardvariablen erben und Sie werden die binäre Größe abschneiden, da Sie bereits deklarierte Symbole wiederverwenden.

Nun zu template<size_t bufferSize> class FixedMemoryStreamWithBuffer . Diese Klasse ist sehr ähnlich wie std::array<std::uint8_t, bufferSize> für die Art und Weise, wie Speicher angegeben und erworben wird. Sie können nicht viel darüber optimieren: Jede Instanziierung ist ein anderer -Typ mit allem, was dazu gehört. Der Compiler kann nicht "verschmelzen" oder etwas Magisches an ihnen vornehmen: Jede Instanz muss ihren eigenen Typ haben. Entweder greifen Sie auf std::vector zurück oder Sie haben spezialisierte Teile mit fester Größe wie 32, 128 usw. und für alle Werte dazwischen wählen Sie die richtige; Dies kann vollständig zur Kompilierzeit erreicht werden, also keine Laufzeitkosten.

    
edmz 19.12.2017 19:33
quelle
2

Beachten Sie zunächst, dass der Compiler auch für jeden FixedMemoryStreamWithBuffer & lt; & gt; separate v-table (sowie RTTI-Informationen) generiert. Typ Instanz, sowie jede Klasse in der Vererbungskette.

Um das Problem zu lösen, würde ich Containment anstelle von Vererbung mit einer Konvertierungsfunktion und / oder einem Operator innerhalb von

empfehlen %Vor%     
Alex Robenko 21.12.2017 06:19
quelle

Tags und Links