Embedded C ++: STL verwenden oder nicht?

74

Ich war schon immer ein Embedded-Software-Ingenieur, aber normalerweise auf Schicht 3 oder 2 des OSI-Stacks. Ich bin nicht wirklich ein Hardware-Typ. Ich habe im Allgemeinen immer Telekommunikationsprodukte hergestellt, normalerweise Hand- / Mobiltelefone, was im Allgemeinen so etwas wie einen ARM 7-Prozessor bedeutet.

Jetzt befinde ich mich in einer allgemeineren eingebetteten Welt, in einem kleinen Start-up, in dem ich möglicherweise zu "nicht so leistungsstarken" Prozessoren übergehe (es gibt das subjektive Bit) - ich kann nicht vorhersagen, welche.

Ich habe viel über die Debatte über die Verwendung von STL in C ++ in eingebetteten Systemen gelesen und es gibt keine eindeutige Antwort. Es gibt einige kleine Bedenken hinsichtlich der Portabilität und einige hinsichtlich der Codegröße oder der Laufzeit, aber ich habe zwei Hauptprobleme:
1 - Ausnahmebehandlung; Ich bin mir immer noch nicht sicher, ob ich es verwenden soll (siehe Embedded C ++: Ausnahmen verwenden oder nicht? )
2 - Ich mag die dynamische Speicherzuweisung in eingebetteten Systemen aufgrund der damit verbundenen Probleme nicht. Ich habe im Allgemeinen einen Pufferpool, der zur Kompilierungszeit statisch zugewiesen wird und der nur Puffer mit fester Größe bereitstellt (wenn keine Puffer vorhanden sind, System zurücksetzen). Die STL führt natürlich eine Menge dynamischer Zuweisungen durch.

Jetzt muss ich die Entscheidung treffen, ob ich die STL verwenden oder darauf verzichten möchte - für das gesamte Unternehmen für immer (es geht um einige Kern-S / W).

In welche Richtung springe ich? Super sicher und viel von dem verlieren, was C ++ ausmacht (imo, es ist mehr als nur die Sprachdefinition) und vielleicht später auf Probleme stoßen oder jetzt viel Ausnahmebehandlung und vielleicht etwas anderen Code hinzufügen müssen?

Ich bin versucht, einfach mit Boost zu arbeiten , aber 1) ich bin nicht sicher, ob es auf jeden eingebetteten Prozessor portiert, den ich verwenden möchte, und 2) auf ihrer Website sagen sie, dass sie bestimmte Teile davon nicht garantieren / empfehlen für eingebettete Systeme (insbesondere FSMs, was seltsam erscheint). Wenn ich mich für Boost entscheide und wir später ein Problem finden ...

Mawg sagt, Monica wieder einzusetzen
quelle
8
STL ist Teil der C ++ - Sprache. Wenn Sie sich Sorgen um den Speicher machen, ersetzen Sie den Operator new und löschen Sie ihn durch Ihre eigene Speicherverwaltung.
GManNickG
6
Haben Sie die uSTL überprüft? ustl.sourceforge.net
Manuel
1
Sieht gut aus, danke. Ich muss mich natürlich eingehender mit Portabilität befassen.
Mawg sagt, Monica
3
Die meisten C ++ - Container verwenden ein "Allocator" -Objekt, das angibt, wo dynamischer Speicher abgerufen werden soll. Sie können ganz einfach die vollständige Kontrolle über den Speicher haben. (Nicht alles braucht Allokatoren, aber die meisten Dinge tun es)
Mooing Duck
1
Schauen Sie sich Meyers Folien über die Verwendung von C ++ für Embedded an: htrd.su/wiki/_media/zhurnal/2013/03/28/…
Claudio

Antworten:

35

Super sicher und viel von dem verlieren, was C ++ ausmacht (imo, es ist mehr als nur die Sprachdefinition) und vielleicht später auf Probleme stoßen oder jetzt viel Ausnahmebehandlung und vielleicht etwas anderen Code hinzufügen müssen?

Wir haben eine ähnliche Debatte in der Spielwelt und die Leute kommen auf beiden Seiten runter. Was den zitierten Teil betrifft, warum sollten Sie sich Sorgen machen, "viel von dem zu verlieren, was C ++ ausmacht"? Wenn es nicht pragmatisch ist, verwenden Sie es nicht. Es sollte keine Rolle spielen, ob es "C ++" ist oder nicht.

Führen Sie einige Tests durch. Können Sie die Speicherverwaltung von STL auf eine Weise umgehen, die Sie zufriedenstellt? Wenn ja, hat sich die Mühe gelohnt? Viele Probleme, die STL und Boost lösen sollen, treten einfach nicht auf, wenn Sie eine zufällige dynamische Speicherzuweisung vermeiden möchten. Löst STL ein bestimmtes Problem, mit dem Sie konfrontiert sind?

Viele Menschen haben STL in engen Umgebungen angegangen und waren damit zufrieden. Viele Leute meiden es einfach. Einige Leute schlagen völlig neue Standards vor . Ich glaube nicht, dass es eine richtige Antwort gibt.

Dan Olson
quelle
1
Danke, Dan, das und andere (auch abgestimmt) haben mich zum Nachdenken gebracht. Da wir ein eingebettetes System haben, haben wir unseren eigenen Speicherpool. STL ist für uns hauptsächlich für Containerklassen nützlich. aber wir maximieren sie zur Initialisierungszeit. Entweder leben wir damit und regeln nach dem Systemstart keine STL-Zuweisung, oder wir können einfach alte Arrays (von Zeigern auf statisch zugewiesene Objekte) verwenden
Mawg sagt, Monica
47

Ich arbeite jeden Tag an eingebetteten Echtzeitsystemen. Natürlich kann meine Definition des eingebetteten Systems anders sein als Ihre. Wir nutzen jedoch die STL und Ausnahmen in vollem Umfang und haben keine unüberschaubaren Probleme. Wir verwenden auch dynamischen Speicher (mit einer sehr hohen Rate; Zuweisung vieler Pakete pro Sekunde usw.) und mussten noch nicht auf benutzerdefinierte Zuweiser oder Speicherpools zurückgreifen. Wir haben sogar C ++ in Interrupt-Handlern verwendet. Wir verwenden keinen Boost, sondern nur, weil eine bestimmte Regierungsbehörde uns nicht zulässt.

Nach unserer Erfahrung können Sie in der Tat viele moderne C ++ - Funktionen in einer eingebetteten Umgebung verwenden, solange Sie Ihren Kopf verwenden und Ihre eigenen Benchmarks durchführen. Ich empfehle Ihnen dringend, Scott Meyers Effective C ++ 3rd Edition sowie die C ++ - Codierungsstandards von Sutter und Alexandrescu zu verwenden, um Sie bei der Verwendung von C ++ mit einem vernünftigen Programmierstil zu unterstützen.

Bearbeiten: Nachdem ich 2 Jahre später eine positive Bewertung dazu erhalten habe, möchte ich ein Update veröffentlichen. Wir sind in unserer Entwicklung viel weiter fortgeschritten und haben endlich Stellen in unserem Code erreicht, an denen die Standardbibliothekscontainer unter Hochleistungsbedingungen zu langsam sind. Hier haben wir tatsächlich auf benutzerdefinierte Algorithmen, Speicherpools und vereinfachte Container zurückgegriffen. Das ist das Schöne an C ++: Sie können die Standardbibliothek verwenden und all die guten Dinge erhalten, die sie für 90% Ihrer Anwendungsfälle bietet. Sie werfen nicht alles weg, wenn Sie auf Probleme stoßen, sondern optimieren einfach die Problemstellen von Hand.

Brian Neal
quelle
3
+1, nützliche Antwort. Aber ich denke, Sie wissen nicht so viel über Ausnahmen oder aufgeblähten Code wie Sie denken - bitte lesen Sie meine Kommentare als Antwort auf Ihre in den Posts anderer.
j_random_hacker
1
Wo genau in meiner Antwort erscheint der Ausdruck "Code Bloat"? Ich schätze die +1, aber bitte richten Sie Ihre Kommentare auf diese spezielle Antwort.
Brian Neal
klingt großartig (und ja, diese beiden Bücher (und die kompletten Meyers "effektiv ...") sitzen gerade neben meinem Monitor. Welche Art von Prozessoren zielen Sie ab?
Mawg sagt, Monica wird
Dürfen Sie Boost schon benutzen?
SS Anne
25

Die anderen Beiträge haben sich mit den wichtigen Themen der dynamischen Speicherzuweisung, Ausnahmen und möglichem Aufblähen des Codes befasst. Ich möchte nur hinzufügen: Vergiss nicht <algorithm>! Unabhängig davon , ob Sie STL - Vektoren oder Ebene C - Arrays und Zeiger, können Sie verwenden sort(), binary_search(), random_shuffle()die Funktionen für den Aufbau und die Verwaltung von Halden usw. Diese Routinen werden mit ziemlicher Sicherheit schneller und weniger Buggy als Versionen zum Selberbauen.

Beispiel: Wenn Sie nicht sorgfältig darüber nachdenken, führt ein von Ihnen selbst erstellter Shuffle-Algorithmus wahrscheinlich zu verzerrten Verteilungen . random_shuffle()Gewohnheit.

j_random_hacker
quelle
19

Paul Pedriana von Electronic Arts schrieb 2007 eine lange Abhandlung darüber, warum die STL für die Entwicklung eingebetteter Konsolen ungeeignet war und warum sie ihre eigenen schreiben mussten. Es ist ein ausführlicher Artikel, aber die wichtigsten Gründe waren:

  1. STL-Allokatoren sind langsam, aufgebläht und ineffizient
  2. Compiler sind eigentlich nicht sehr gut darin, all diese tiefen Funktionsaufrufe zu integrieren
  3. STL-Allokatoren unterstützen keine explizite Ausrichtung
  4. Die STL-Algorithmen, die mit GCC und MSVCs STL geliefert werden, sind nicht sehr leistungsfähig, da sie sehr plattformunabhängig sind und daher viele Mikrooptimierungen übersehen, die einen großen Unterschied machen können.

Vor einigen Jahren hat unser Unternehmen beschlossen, die STL überhaupt nicht zu verwenden, sondern stattdessen ein eigenes Containersystem zu implementieren, das maximal leistungsfähig, einfacher zu debuggen und speicherkonservativer ist. Es war viel Arbeit, aber es hat sich um ein Vielfaches zurückgezahlt. In unserem Bereich konkurrieren Produkte jedoch darum, wie viel sie mit einer bestimmten CPU- und Speichergröße auf 16,6 ms erreichen können.

Ausnahmen: Sie sind auf Konsolen langsam , und jeder, der Ihnen etwas anderes sagt, hat nicht versucht, sie zeitlich zu steuern. Durch einfaches Kompilieren mit aktivierten Funktionen wird das gesamte Programm aufgrund des erforderlichen Prolog- / Epilog-Codes verlangsamt. Messen Sie es selbst, wenn Sie mir nicht glauben. Bei geordneten CPUs ist es sogar noch schlimmer als beim x86. Aus diesem Grund unterstützt der von uns verwendete Compiler nicht einmal C ++ - Ausnahmen.

Der Leistungsgewinn besteht nicht so sehr darin, die Kosten eines Ausnahmewurfs zu vermeiden, sondern darin, Ausnahmen vollständig zu deaktivieren.

Crashworks
quelle
12
Sie haben einen Artikel aus dem Jahr 2006 verlinkt, der jetzt veraltet ist. C ++ - Ausnahmen sind bei anständigen modernen Compilern nicht langsam. Wenn Sie es mit einem eingebetteten System zu tun haben, für das es keinen anständigen modernen Copmiler gibt, haben Sie ein Problem - aber eine Decke mit dem Titel "Ausnahmen: Sie sind langsam" zu geben, ist absolut falsch.
JoeG
15
Anerkannte C ++ - Experten wie Herb Sutter und Andrei Alexandrescu sind mit Ihrer Aussage "Ausnahmen sind langsam" nicht einverstanden. Wenn Sie keine Ausnahmen verwenden, sind Sie jetzt selbst für das Schreiben und Überprüfen von Fehlerrückgabecodes verantwortlich. Dieser Code ist fast immer weniger effizient und im Vergleich zu dem Code, den moderne Compiler für Ausnahmen ausgeben. Darüber hinaus ist der Code, den die Leute schreiben (wenn sie sich überhaupt die Mühe machen, ihn zu schreiben), um Fehlercodes zu überprüfen, oft voller Fehler und Irrtümer.
Brian Neal
4
Ausnahmen sind nicht sehr langsam, verursachen jedoch einen Laufzeitaufwand ungleich Null für mindestens einen gängigen modernen Compiler (MSVC ++ 9), selbst wenn keine Ausnahme jemals ausgelöst wird. Versuchen Sie dazu, pastebin.com/m1fb29a45 mit /EHaund dann mit /EHsc/ Fa zu kompilieren (nicht zu verknüpfen) , um eine Baugruppenliste zu erstellen. In beiden Fällen wird die SEH-Verwaltung (Structured Exception Handling) von Win32 eingeführt. Dies ist das zusätzliche Verschieben von Daten auf den Stapel und das Einstellen des FSSegmentregisters.
j_random_hacker
10
Der Artikel stammt aus dem Jahr 2006, aber meine eigenen Zeitangaben stammen aus dem August 2009. Ich habe die ganze Theorie darüber gelesen, dass Ausnahmen nicht mehr langsam sind, aber sie bestätigen nicht die tatsächlichen Messungen, die ich durchgeführt habe .
Crashworks
2
Brian: Das sind die Punkte von EA, nicht meine, aber # 4 wurde empirisch ermittelt. Grundsätzlich haben sie ihre eigenen Implementierungen der Container geschrieben und festgestellt, dass sie viel schneller als die STLs liefen. Daher ist die STL nicht maximal effizient.
Crashworks
15

Lassen Sie mich zunächst sagen, dass ich seit einigen Jahren keine eingebettete Arbeit mehr geleistet habe und niemals in C ++. Mein Rat ist also jeden Cent wert, den Sie dafür bezahlen ...

Die von STL verwendeten Vorlagen generieren niemals Code, den Sie nicht selbst generieren müssten, sodass ich mir keine Sorgen über das Aufblähen von Code machen würde.

Die STL löst keine eigenen Ausnahmen aus, daher sollte dies kein Problem darstellen. Wenn Ihre Klassen nicht werfen, sollten Sie in Sicherheit sein. Teilen Sie Ihre Objektinitialisierung in zwei Teile, lassen Sie den Konstruktor ein Bare-Bones-Objekt erstellen und führen Sie dann eine Initialisierung durch, die in einer Elementfunktion fehlschlagen könnte, die einen Fehlercode zurückgibt.

Ich denke, mit allen Containerklassen können Sie Ihre eigene Zuordnungsfunktion definieren. Wenn Sie also aus einem Pool zuordnen möchten, können Sie dies ermöglichen.

Mark Ransom
quelle
1
+1, ich denke, dies ist eines der wenigen Male, dass es eine gute Idee ist, Bauarbeiten von Konstrukteuren zu entfernen.
j_random_hacker
6
Was meinst du mit "die STL wirft keine eigenen Ausnahmen"? Was ist, wenn Sie vector :: at mit einem Index außerhalb des Bereichs aufrufen? Sie können auch E / A-Streams so konfigurieren, dass Ausnahmen ausgelöst werden. Außerdem können Vorlagen mehr Code generieren als Sie, wenn Sie ihn von Hand geschrieben haben. Siehe das Beispiel in Stroustrup zum Kombinieren einer Vorlage mit void *, um ein solches Aufblähen zu reduzieren.
Brian Neal
4
@ Brian: vector::at()ist ein gutes Beispiel. Es wäre genauer zu sagen, dass die STL so verwendet werden kann, dass sie niemals Ausnahmen erzeugt (hier durch Verwendung operator[]()anstelle von at()) und ohne zusätzliche Kompromisse einzugehen.
j_random_hacker
@Brian: In Bezug auf das Aufblähen von Code werden Funktionen mit identischem Objektcode zum Zeitpunkt der Verknüpfung mit MSVC ++ entfernt, wenn Sie dem Compiler / Gy und dem Linker / OPT: ICF angeben. Ich glaube, der GNU-Linker kann das Gleiche tun.
j_random_hacker
1
@ Brian Neal, ich habe es vergessen vector::atund wahrscheinlich auch ein paar andere - danke für die Klarstellung. Es sollte möglich sein, Ihre Standardbibliotheksdateien nach "throw" zu durchsuchen und alle "Ausnahmen" zu meiner übermäßig verallgemeinerten Aussage zu finden.
Mark Ransom
8

Das Open-Source-Projekt "Embedded Template Library (ETL)" zielt auf die üblichen Probleme mit der in eingebetteten Anwendungen verwendeten STL ab, indem eine Bibliothek bereitgestellt / implementiert wird:

  • deterministisches Verhalten
  • "Erstellen Sie eine Reihe von Containern, bei denen die Größe oder maximale Größe zum Zeitpunkt der Kompilierung festgelegt wird. Diese Container sollten weitgehend den in der STL bereitgestellten Containern mit einer kompatiblen API entsprechen."
  • Keine dynamische Speicherzuordnung
  • Keine RTTI erforderlich
  • wenig Nutzung virtueller Funktionen (nur wenn unbedingt erforderlich)
  • Satz Behälter mit fester Kapazität
  • Cache-freundliche Speicherung von Containern als kontinuierlich zugeordneter Speicherblock
  • reduzierte Container-Code-Größe
  • typsichere intelligente Aufzählungen
  • CRC-Berechnungen
  • Prüfsummen & Hash-Funktionen
  • Varianten = Art typsicherer Gewerkschaften
  • Auswahl von Asserts, Ausnahmen, Fehlerbehandlungsroutine oder keine Fehlerprüfung
  • stark gerätetestet
  • gut dokumentierter Quellcode
  • und andere Funktionen ...

Sie können auch eine kommerzielle C ++ - STL für eingebettete Entwickler in Betracht ziehen, die von ESR Labs bereitgestellt wird.

thinwybk
quelle
5
  1. Für die Speicherverwaltung können Sie einen eigenen Allokator implementieren, der Speicher aus dem Pool anfordert. Und alle STL-Container haben eine Vorlage für den Allokator.

  2. Ausnahmsweise löst STL nicht viele Ausnahmen aus. Im Allgemeinen sind die häufigsten: In Ihrem Fall sollte das System zurückgesetzt werden, damit Sie im Allokator zurücksetzen können. andere sind beispielsweise außerhalb der Reichweite, Sie können es vom Benutzer vermeiden.

  3. Ich denke, Sie können STL im eingebetteten System verwenden :)

ddh
quelle
4

Zusätzlich zu allen Kommentaren würde ich vorschlagen, dass Sie den technischen Bericht zur C ++ - Leistung lesen, der sich speziell mit Themen befasst, an denen Sie interessiert sind: Verwendung von C ++ in Embedded (einschließlich harter Echtzeitsysteme); wie die Ausnahmebehandlung normalerweise implementiert wird und welchen Overhead sie hat; Overhead der kostenlosen Filialzuweisung.

Der Bericht ist wirklich gut, ebenso wie viele beliebte Details zur C ++ - Leistung.

Alexander Poluektov
quelle
3

Dies hängt im Wesentlichen von Ihrem Compiler und der Größe Ihres Arbeitsspeichers ab. Wenn Sie mehr als ein paar KB RAM haben, hilft eine dynamische Speicherzuweisung sehr. Wenn die Implementierung von malloc aus der Standardbibliothek, die Sie haben, nicht auf Ihre Speichergröße abgestimmt ist, können Sie Ihre eigene schreiben, oder es gibt nette Beispiele wie mm_malloc von Ralph Hempel , mit denen Sie Ihre neuen Operatoren und Löschoperatoren darüber schreiben können .

Ich stimme nicht mit denen überein, die das Mem wiederholen, dass Ausnahmen und stl-Container zu langsam oder zu aufgebläht sind usw. Natürlich fügt es etwas mehr Code hinzu als das Malloc eines einfachen C, aber die vernünftige Verwendung von Ausnahmen kann den Code viel klarer und klarer machen Vermeiden Sie zu viele Fehler beim Überprüfen des Klappentextes in C.

Man muss bedenken, dass STL-Allokatoren ihre Allokationen in Zweierpotenzen erhöhen, was bedeutet, dass sie manchmal einige Neuzuweisungen vornehmen, bis sie die richtige Größe erreicht haben, die Sie mit Zurückhaltung verhindern können, damit sie so billig wie ein Malloc des gewünschten wird Größe, wenn Sie die Größe kennen, die Sie trotzdem zuweisen möchten.

Wenn Sie beispielsweise einen großen Puffer in einem Vektor haben, wird möglicherweise irgendwann eine Neuzuweisung durchgeführt und das 1,5-fache der Speichergröße verbraucht, die Sie zu einem bestimmten Zeitpunkt beim Neuzuweisen und Verschieben von Daten verwenden möchten. (Zum Beispiel werden irgendwann N Bytes zugewiesen, Sie fügen Daten über Anhängen oder einen Einfügeiterator hinzu und es werden 2N Bytes zugewiesen, die ersten N kopiert und N freigegeben. Irgendwann sind 3N Bytes zugewiesen.)

Am Ende hat es also viele Vorteile und zahlt sich aus, wenn Sie wissen, was Sie tun. Sie sollten ein wenig darüber wissen, wie C ++ funktioniert, um es ohne Überraschungen in eingebetteten Projekten zu verwenden.

Und für den Mann mit den festen Puffern und dem Zurücksetzen können Sie jederzeit innerhalb des neuen Operators oder was auch immer zurücksetzen, wenn Sie nicht genügend Speicher haben. Dies würde jedoch bedeuten, dass Sie ein schlechtes Design erstellt haben, das Ihren Speicher erschöpfen kann.

Eine Ausnahme, die mit ARM Realview 3.1 ausgelöst wird:

--- OSD\#1504 throw fapi_error("OSDHANDLER_BitBlitFill",res);
   S:218E72F0 E1A00000  MOV      r0,r0
   S:218E72F4 E58D0004  STR      r0,[sp,#4]
   S:218E72F8 E1A02000  MOV      r2,r0
   S:218E72FC E24F109C  ADR      r1,{pc}-0x94 ; 0x218e7268
   S:218E7300 E28D0010  ADD      r0,sp,#0x10
   S:218E7304 FA0621E3  BLX      _ZNSsC1EPKcRKSaIcE       <0x21a6fa98>
   S:218E7308 E1A0B000  MOV      r11,r0
   S:218E730C E1A0200A  MOV      r2,r10
   S:218E7310 E1A01000  MOV      r1,r0
   S:218E7314 E28D0014  ADD      r0,sp,#0x14
   S:218E7318 EB05C35F  BL       fapi_error::fapi_error   <0x21a5809c>
   S:218E731C E3A00008  MOV      r0,#8
   S:218E7320 FA056C58  BLX      __cxa_allocate_exception <0x21a42488>
   S:218E7324 E58D0008  STR      r0,[sp,#8]
   S:218E7328 E28D1014  ADD      r1,sp,#0x14
   S:218E732C EB05C340  BL       _ZN10fapi_errorC1ERKS_   <0x21a58034>
   S:218E7330 E58D0008  STR      r0,[sp,#8]
   S:218E7334 E28D0014  ADD      r0,sp,#0x14
   S:218E7338 EB05C36E  BL       _ZN10fapi_errorD1Ev      <0x21a580f8>
   S:218E733C E51F2F98  LDR      r2,0x218e63ac            <OSD\#1126>
   S:218E7340 E51F1F98  LDR      r1,0x218e63b0            <OSD\#1126>
   S:218E7344 E59D0008  LDR      r0,[sp,#8]
   S:218E7348 FB056D05  BLX      __cxa_throw              <0x21a42766>

Scheint nicht so beängstigend und es wird kein Overhead in {} Blöcken oder Funktionen hinzugefügt, wenn die Ausnahme nicht ausgelöst wird.

piotr
quelle
1

Das größte Problem mit STL in eingebetteten Systemen ist das Problem der Speicherzuweisung (das, wie Sie sagten, viele Probleme verursacht).

Ich würde ernsthaft nachforschen, um eine eigene Speicherverwaltung zu erstellen, die durch Überschreiben der Operatoren new / delete erstellt wird. Ich bin mir ziemlich sicher, dass es mit ein bisschen Zeit geschafft werden kann, und es lohnt sich mit ziemlicher Sicherheit.

Was die Ausnahme betrifft, würde ich nicht dorthin gehen. Ausnahmen stellen eine ernsthafte Verlangsamung Ihres Codes dar, da sie dazu führen, dass jeder einzelne Block ( { }) vorher und nachher Code enthält, wodurch die Ausnahme abgefangen und alle darin enthaltenen Objekte zerstört werden können. Ich habe keine genauen Daten dazu zur Hand, aber jedes Mal, wenn ich dieses Problem gesehen habe, habe ich überwältigende Beweise für eine massive Verlangsamung gesehen, die durch die Verwendung von Ausnahmen verursacht wurde.

Bearbeiten:
Da viele Leute Kommentare geschrieben haben, die besagen, dass die Ausnahmebehandlung nicht langsamer ist, dachte ich, ich würde diese kleine Notiz hinzufügen (danke für die Leute, die dies in Kommentaren geschrieben haben, ich dachte, es wäre gut, sie hier hinzuzufügen).

Der Grund, warum die Ausnahmebehandlung Ihren Code verlangsamt, besteht darin, dass der Compiler sicherstellen muss, dass jeder Block ( {}) von der Stelle, an der eine Ausnahme ausgelöst wird, bis zu der Stelle, an der er behandelt wird, alle darin enthaltenen Objekte freigeben muss. Dies ist Code, der jedem Block hinzugefügt wird, unabhängig davon, ob jemals jemand eine Ausnahme auslöst oder nicht (da der Compiler zur Kompilierungszeit nicht feststellen kann, ob dieser Block Teil einer Ausnahmekette ist).

Natürlich könnte dies eine alte Methode sein, um Dinge zu tun, die in neueren Compilern viel schneller geworden sind (ich bin nicht gerade auf dem neuesten Stand der C ++ - Compileroptimierungen). Der beste Weg, dies zu wissen, besteht darin, nur einen Beispielcode mit aktivierten und deaktivierten Ausnahmen (der einige verschachtelte Funktionen enthält) auszuführen und den Unterschied zeitlich zu bestimmen.

Edan Maor
quelle
6
-1 für völliges Unverständnis darüber, wie Ausnahmen implementiert werden.
Billy ONeal
3
Ausnahmen verursachen bei der Implementierung durch moderne Compiler normalerweise keinen Laufzeitaufwand, es sei denn, eine Ausnahme wird tatsächlich ausgelöst. Und wenn Sie Ausnahmen sorgfältig verwenden (und nicht für die normale Flusskontrolle), ist die Leistung kein Problem, wenn etwas schief geht.
Brian Neal
3
Hast du das geplant, Brian? Als ich das letzte Mal versuchte, es zu messen (letzten Sommer), stellte ich fest, dass das einfache Aktivieren von Ausnahmen und das Abwickeln von Stapeln in den Compilereinstellungen zu einer Verlangsamung führte, unabhängig davon, ob ich tatsächlich Ausnahmen ausgelöst habe oder nicht.
Crashworks
2
@Brian: Zumindest unter Win32 muss jeder tryBlock einen EXCEPTION_REGISTRATIONBlock auf dem Stapel einrichten und das FS-Register darauf richten . Dies geschieht unabhängig davon, ob tatsächlich Ausnahmen auftreten. Quelle: microsoft.com/msj/0197/exception/exception.aspx Außerdem muss der Compiler jedem Block Code hinzufügen, der Objekte mit nicht trivialen Destruktoren deklariert, es sei denn, er kann nachweisen, dass innerhalb des Blocks keine Ausnahme auftreten kann. Wie werden diese Objekte sonst beim Abwickeln des Stapels zerstört?
j_random_hacker
3
@Brian: Interessanterweise habe ich gerade eine Variation meines Pastebin-Snippets unter Linux x86 g ++ 4.2.1 ausprobiert. Der einzige Unterschied bestand darin, dass zusätzliche 32 Bytes auf dem Stapel zugewiesen wurden - aber nicht darauf geschrieben wurden. Wenn also in einer Funktion lokale Variablen vorhanden sind, die nicht in Register passen (was bedeutet, dass ohnehin Speicherplatz auf dem Stapel zugewiesen werden muss), werden keine zusätzlichen Anweisungen ausgeführt, wenn keine Ausnahmen abgefangen oder ausgelöst werden . Sehr beeindruckend!
j_random_hacker
1

In unserem Embedded-Scanner-Projekt haben wir ein Board mit ARM7-CPU entwickelt, und STL brachte keine Probleme mit sich. Sicherlich sind die Projektdetails wichtig, da die dynamische Speicherzuweisung für viele heute verfügbare Boards und Projekttypen möglicherweise kein Problem darstellt.

mEbert
quelle
+1 ein guter Punkt. Die Prozessoren in "eingebetteten" Projekten werden immer leistungsfähiger. Mein aktueller Atmel-Prozessor ist eine 32-Bit-UC3-Serie. Als ich anfing, bedeutete eingebettet 4 oder 8 Bits. Der 32-Bit-Prozessor verfügt jedoch nur über 512 KB Benutzerspeicher, was die Dinge etwas eng macht. Sie haben keine Speicherprobleme?
Mawg sagt, Monica