Unangenehmes Problem mit sprintf_s
-
Hallo zusammen
Ich habe ein wirklich unangenehmes Problem mit der sprintf_s Funktion, welche ich jetzt bereits an mehreren Stellen angetroffen habe und mich doch sehr beunruhigt. Und zwar scheint diese Funktion ein undefiniertes Verhalten an den Tag zu legen, wenn man ihm eine falsche Puffergrösse angibt, selbst wenn kein Pufferüberlauf stattfindet:char szBuf[16]; sprintf_s(szBuf,4096,"Hallo");
Ich meine, ich verursache ja keinen Pufferüberlauf? Leider ist es mir nicht gelunden eine einfache Konsolenapplikation zu schreiben, welche die entsprechenden Symptome aufweist, daher zeige ich mal, wo es in unserer Thesis auftritt:
// ---------------------------------- method "ShowAvailableResolutions" ---------------------------------- // This Script Function displays all available resolutions for the currently selected adapter. // Author: Samuel Lörtscher // ------------------------------------------------------------------------------------------------------- void MyScriptService::ShowAvailableResolutions(char *Respond,uint32 BufferSize,char **Params, uint32 ParamCount){ // try to obtain the active IVideoService IVideoService *svVdo = Services::GetInstance()->GetService<IVideoService>(false); // check if such a IVideoService is currently available if(svVdo){ // write the header uint32 cChr = sprintf_s(Respond,BufferSize,"Zeige verfügbare Auflösungen\n"); // start a loop for iterating over each currently available video modes Iterator<VideoMode*> *pItr = svVdo->GetAvailableVideoModes()->GetItems(); for(uint32 i=0;pItr->Next();++i){ // write the resolution of the current video mode VideoMode *pVm = pItr->GetItem(); cChr += sprintf_s(Respond+cChr,BufferSize-cChr,"%u: %ux%u %uHz\n",i,pVm->Width,pVm->Height,pVm->RefreshRate); } } // otherwise write that no such IService is currently available else strcpy_s(Respond,BufferSize,"Es ist kein IVideoService vefügbar"); } // -------------------------------------------------------------------------------------------------------
Nehme ich auf der 7. untersten Zeile das -cChr raus, stürzt die gesamte Applikation gnadenlos ab, wohlgemerkt keine Assertion (welche sprintf_s im Fall eines Pufferüberlaufs generiert)
// write the resolution of the current video mode VideoMode *pVm = pItr->GetItem(); cChr += sprintf_s(Respond+cChr,BufferSize/*-cChr*/,"%u: %ux%u %uHz\n",i,pVm->Width,pVm->Height,pVm->RefreshRate);
Pängggggggg.......
Also das perverse ist noch, dass es nicht sofort abstürzt, diese Methode wird von IScriptService::ExecuteScript aufgerufen:// call the appropriate function if it's registered or respond // that the desired function doesn't exist otherwise if(this->dcFnc->KeyExists(szNme)) (this->*(this->dcFnc->Find(szNme)))(Respond,BufferSize,aPrm,cPrm); else strcpy_s(Respond,BufferSize,"Funktion nicht gefunden");
[/cpp]
Abgespeichert ist das Ganze folgendermassen:
// create the required RedBlackTree for storing all associations between // Script Function calls and the corresponding binary execution code this->dcFnc = new RedBlackTree<string*,void (MyScriptService::*)(char*,uint32,char**,uint32)>(); this->dcFnc->Insert("IVideoService.ShowAvailableResolutions",&MyScriptService::ShowAvailableResolutions);
Und IScriptService::ExecuteScript wird von Console::Update aufgerufen:
// try to obtain an IScriptService (may be null) IScriptService *svScp = Services::GetInstance()->GetService<IScriptService>(false); // execute the command if a IScriptService is available or inform the user // that no service is available to respont the request otherwise if(svScp){ // execute the script typed into the console char szBuf[MAX_STR]; svScp->ExecuteScript(&this->szOut[this->idRow*this->cCol],szBuf,MAX_STR);
Und nachdem ich ExecuteScript aufgerufen habe (breakpoint) ist das gesamte Stackframe völlig zertört, selbst der this pointer zeigt plötzlich auf eine völlig andere Adresse.
Lasse ich das -cChr drinnen oder verwende ich anstelle von sprintf_s sprintf läuft das Programm noch Tage später...
Vielleicht denkt ihr jetzt, der Puffer sei zu klein, das würde natürlich alles erklären, aber glaubt mir, der ist nicht zu klein und wenn er es wäre würde ja eine Assertion geworfen, wenn ich -cChr drinn lasse. Der Puffer ist genau 2048 bytes gross wovon ich in der ShowAvailableResolutions ca. 200 Bytes benutze.
Eigentlich könnte ich ja zufrieden sein, es läuft ja jtzt, aber ich bin erst zufrieden, wenn ich weiss, was diese Funktion genau macht und der den Stack zerfetzt. Was mich am meisten wundert ist auch, dass er ja nicht das lokale Stackframe überschreibt, in welcher der fehlerhafte Code ausgeführt wurde, sonst würde er ja die Rücksprungadresse nicht mehr finden. Aber er sprint ja noch 2 Funktionen zurück und erst dann ist plötzlich alles kaputt...
-
Anscheinend wird in der Debug-Variante der gesamte ungenutzte Bereich des Puffers mit 0xFE gefüllt.
-
Interessieren würde mich noch, was das eigentlich mit C++ zu tun hat?
sprintf_s
gibt es im C++ Standard nicht.Grüssli
-
@Dravere
Mit ANSI C++ IMHO nichts, aber ich dachte mir, im C Forum hätten Sie vermutlich den Code nicht verstanden...@MFK
Bist du sicher oder vermutest du das einfach?
-
Ishildur schrieb:
Bist du sicher oder vermutest du das einfach?
du übergibst ungültige Werte, dadurch ist das Verhalten nicht mehr genau definiert. Bufferoverflow protection könnte dir hier eben die Anwendung abschiessen.
Genaures steht aber in der MSDN auch nicht, nur dass die Buffersize eben der Puffer größe entsprechen muss. Warum verwendest du die *_s Varianten wenn du sie nicht korrekt nutzt? Dann nimm doch gleich sprintf...
-
@Shade Of Mine
Ich benutze Sie ja schon korrekt, es war zunächst ein unbeabsichtiger Fehler. Was ich einfach doof finde ist, dass ich nun anscheinend durch die Benutzung der "Save" Varianten in Wahrheit einfach noch eine zusätzliche Fehlerquelle einbaue.Normal "Unsave": Der Buffer zu klein und Bumm...
"Save!" : Der Buffer zu klein ODER Size Parameter falsch berechnet und Bumm....Was ist daran Save?
-
Ishildur schrieb:
Was ist daran Save?
Die Überlaufsüberprüfung. Aber wenn du da falsche Werte angibst... Kristallkugeln gibts halt noch keine...
PS:
bzw die Kristallkugel ist ja dann das BUMM das nämlich immer kommt. Was viel besser als das vielleicht BUMM bei sprintf ist
-
Hehe ja OK. Ich bin ja schon sehr froh, dass dies ein bekanntes Phänomen von sprintf_s ist, ich befürchtete bereits, dass der eigentliche Fehler vielleicht noch viel tiefer sitzt, weil ich das Ganze mit einer simplen Konsolenapplikation nicht nachbilden konnte:
int main(){ char szBuf[16]; sprintf_s(szBuf,4096,"Hallo"); return 0; }
Dieses Programm stürzt nämmlich aus irgendeinem Grund nicht ab?? Der müsste doch eigentlich die Grenzen des aktuellen Threadstacks überschreiben und in jedem Fall eine Speicherschutzverletzung auslösen? Wieso passiert dann bei diesem Code nichts?
-
Ich finde es immer wieder witzig, wie Leute probieren mit undefiniertem Verhalten zu argumentieren. Undefiniertes Verhalten heisst nicht Absturz, es heisst undefiniert
Ishildur schrieb:
Mit ANSI C++ IMHO nichts, aber ich dachte mir, im C Forum hätten Sie vermutlich den Code nicht verstanden...
Und wieso sollten wir es im C++ Forum eher verstehen?
Darf ich auch noch fragen, wieso du
sprintf_s
verwenden willst? Gerade wenn es dir um Sicherheit geht, gäbe es in C++ doch bessere und sichere Möglichkeiten.Grüssli
-
Dravere schrieb:
Darf ich auch noch fragen, wieso du
sprintf_s
verwenden willst? Gerade wenn es dir um Sicherheit geht, gäbe es in C++ doch bessere und sichere Möglichkeiten.Die Umstellung von sprintf auf sprintf_s ist einfach weitaus billiger und zeitsparender als auf streams oder boost.
-
Shade Of Mine schrieb:
Dravere schrieb:
Darf ich auch noch fragen, wieso du
sprintf_s
verwenden willst? Gerade wenn es dir um Sicherheit geht, gäbe es in C++ doch bessere und sichere Möglichkeiten.Die Umstellung von sprintf auf sprintf_s ist einfach weitaus billiger und zeitsparender als auf streams oder boost.
Also im Sinne von:
A> "Wir wollen mehr Sicherheit im Programm!"
B> "Wir benutzen C++, lass uns die Sicherheit von C++ nutzen!"
A> "So sicher soll es auch wieder nicht sein, dass wäre viel zu teuer umzustellen."
B> "..."Aber ok, wie wäre es dann zumindest damit, dass die Puffer auf
std::vector
oderstd::tr1::array
Objekte umgestellt werden? So wird gleich auch die Grösse mitübergeben, welche man dann insprintf_s
verwenden kann.Grüssli
-
Ishildur schrieb:
Dieses Programm stürzt nämmlich aus irgendeinem Grund nicht ab?? Der müsste doch eigentlich die Grenzen des aktuellen Threadstacks überschreiben und in jedem Fall eine Speicherschutzverletzung auslösen? Wieso passiert dann bei diesem Code nichts?
Für den Stack wird nicht explizit Speicher angefordert. Es wird einfach drauf los geschrieben. Das Betriebssystem weiß daher gar nicht, dass du in deinem C Programm nur Platz für 16 chars vorsiehst. Der Speicherbereich für den Stack hat einfach zu Beginn eine gewisse Größe (afaik ist 1 MB bei Windows Standard) und kann theoretisch bei Bedarf automatisch weiter wachsen. Daher kommt es dort nicht zu Speicherschutzverletzungen wenn man zu viel drauf schreibt.
Der Grund warum es bei Pufferüberläufen auf dem Stack oft knallt, ist dass dort die Rücksprungadressen stehen. Beim Aufruf einer Funktion wird die aktuelle Adresse dort gespeichert und beim return wird dort wieder hin gesprungen. Wenn die Adresse nun mit irgendeinem falschen Wert überschrieben wurde, springt man ins Nirwana.
-
@Dravere
Ich habe 90% der Applikation mit reinem C implementiert (die C++ Standardbibliothek habe ich nicht angerührt. Ah doch, std::type_info benutze ich. Ich verwende C++ in diesem Projekt ausschliesslich wegen der Templates sowie der Laufzeitpolymorphie. Der Grund liegt darin begründet, dass wir ein Computerspiel als Abschlussarbeit programmieren und Geschwindigkeit an erster Stelle steht. Glaub mir, ich hatte zu beginn die C++ Standard Bibliothek sowie auch die STl umfangreich benutzt, habe jedoch in Folge von Profiling immer mehr C++ Komponenten durch C oder durch eigene Konstrukte ersetzt, weil diese einfach einen nicht hinzunehmenden Overhead hatten. Die std::map benötigte bspw. einfach mal ca. 800 mal länger, um sämtliche Elemente innerhalb der Map zu löschen als bspw. der von mir entwickelte RedBlackTree (Wir haben einige temporäre Bäume, die einmal pro Frame aufgebaut und schliesslich wieder gelöscht werden müssen) Oder die Umstellung einer std::list auf ein natives C Array innerhalb eines kritischen Algorithmus innerhalb der Textengine hatte die Framerate einfach so mal verdoppelt von 500 auf 1000 fps. Die gesamte InGame Konsole benötigt durch die Umstellung von std::string auf cirkuläre c-strings noch ein einziges New und ein einziges Delete während der gesamten Lebensdauer der Applikation und nicht mehr zwischen 10 - 20 news und deletes pro Frame.Natürlich hat das alles einen hohen Preis: Ich muss bspw. dem RedBlackTree sagen, wie gross er maximal werden darf und wie hoch die maximale Suchtiefe sein kann und wehe das wird überschritten, genauso wie bspw. die Konsole. Im Konstruktor übergebe ich die Anzahl Zeilen sowie die Anzahl Spalten und dann alloziiere ich einen entsprechend grossen Speicherbereich (EINMAL) und dann verwalte ich diesen Speicherbereich innerhalb des Programms und kopiere nicht bei jeder neuen Eingabe zig strings hin und her und alloziiere hier wieder Speicher und muss da wieder was freigeben...
Ich weiss doch auch nicht, vielleicht haben wir alles falsch gemacht aber wir haben uns für einen Weg entschieden und den werden wir jetzt auch so zu Ende gehen (in ca. 1.5 Monaten ist Abgabetermin) und da werde ich jtzt sicher nicht wieder alles auf die C++ Bibliothek umstellen (Was wir zu beginn hatten und nicht schnell genug war)...
Eines aber noch Dravere, wie machst du mit C++ iostreams folgendes:
"Mein Name ist %s und wohne in %s seit %s"
"My name is %s and I live in %s since %s"
....
....Diese Strings werden extern gespeichert und werden schliesslich eingelesen und von sprintf_s verarbeitet. Die Positionen der Variablen innerhalb eines Strings kann von Sprache zu Sprache unterschiedlich ausfallen!
-
Ishildur schrieb:
Die std::map benötigte bspw. einfach mal ca. 800 mal länger, um sämtliche Elemente innerhalb der Map zu löschen als bspw. der von mir entwickelte RedBlackTree (Wir haben einige temporäre Bäume, die einmal pro Frame aufgebaut und schliesslich wieder gelöscht werden müssen)
Klasse bauen, fertig. Kann man auch den C code nehmen und kapseln.
Oder die Umstellung einer std::list auf ein natives C Array innerhalb eines kritischen Algorithmus innerhalb der Textengine hatte die Framerate einfach so mal verdoppelt von 500 auf 1000 fps.
Diese framezahlen habe ich jetzt einfach mal ueberlesen. aber list und array sind unterschiedliche datenstrukturen.
Die gesamte InGame Konsole benötigt durch die Umstellung von std::string auf cirkuläre c-strings noch ein einziges New und ein einziges Delete während der gesamten Lebensdauer der Applikation und nicht mehr zwischen 10 - 20 news und deletes pro Frame.
nocopy strings nehmen oder strings aus einem statischen memory pool aufbauen...
Ich weiss doch auch nicht, vielleicht haben wir alles falsch gemacht aber wir haben uns für einen Weg entschieden und den werden wir jetzt auch so zu Ende gehen (in ca. 1.5 Monaten ist Abgabetermin) und da werde ich jtzt sicher nicht wieder alles auf die C++ Bibliothek umstellen (Was wir zu beginn hatten und nicht schnell genug war)...
Der Fehler war von C++ wegzugehen
Denn du hast kein Argument gegen C++ genannt nur gegen bestimmte klassen die sich aber problemlos ersetzen lassen.
Eines aber noch Dravere, wie machst du mit C++ iostreams folgendes:
"Mein Name ist %s und wohne in %s seit %s"
"My name is %s and I live in %s since %s"
....
....Diese Strings werden extern gespeichert und werden schliesslich eingelesen und von sprintf_s verarbeitet. Die Positionen der Variablen innerhalb eines Strings kann von Sprache zu Sprache unterschiedlich ausfallen!
boost::format
aber wenn man C programmiert oder C code warten muss, ist sprintf_s natuerlich eine gute wahl. nur bei einer neuentwicklung... ich weiss nicht.
-
@Shade Of Mine
Klasse bauen, fertig.
Habe ich ja genauso gemacht?
Diese framezahlen habe ich jetzt einfach mal ueberlesen.
Glaubst du mir etwa nicht?
aber list und array sind unterschiedliche datenstrukturen.
Ja ich habe mich verschrieben, war natürlich ein std::vector
Der Punkt dabei war einfach, dass ich für die Textengine (1000fps, was du mir ja nicht glaubst) ein deferred Rendering verwende. Sprich, wenn ich SpriteBatch::DrawText aufrufe, wird noch gar nichts gezeichnet, sondern der entsprechende Text als DrawJob gespeichert. Schliesslich wird einmal pro Frame der komplette Text mit Hilfe eines einzigen Rendercalls gerendert. Dafür muss aber nach jedem Frame der std::vector der Drawjobs komplett entleert werden. Mit einem nativen c - array war dieser Enleerungsprozess jedoch hinfällig, weil ich stattdessen die DrawJobs da lasse wo sie sind und stattdessen eifach den Zeiger wieder auf das erste Element setze, so werden die alten Drawjobs nach und nach überschrieben. (Was eigentlich jedes Betriebssystem auch so macht, wird ja auch nicht jedes bit mit null überschrieben, wenn eine Datei gelöscht wird...)Sprite aSpr[MAX_SPRITE]; uint32 cSpr = 0; void SpriteBatch::DrawText(){ this->aSpr[this->cSpr++] = // kompliziert... :-p } void Render(){ for(uint32 i=0;i<this->cSpr;++i){ // in VertexBuffer abfüllen } IDirect3DDevice9::DrawIndexedPrimitive(); // die Sprites werden nicht gelöscht oder alle auf null gesetzt oder // sonst irgendwas this->cSpr = 0; }
Der Fehler war von C++ wegzugehen
Ja ich habs vielleicht falsch ausgedrückt, als ich sagte, ich hätte zu 90% in C programmiert meinte ich, dass ich fast ausschliesslich die C Standard Bibliothek anstelle der C++ Standard Bibliothek verwende oder dann grad komplett eigene Implementierungen geschrieben habe.
oder strings aus einem statischen memory pool aufbauen
Genau das mache ich doch??
Denn du hast kein Argument gegen C++ genannt nur gegen bestimmte klassen die sich aber problemlos ersetzen lassen.
Genau das mache ich doch?? Ich finde C++ super, nur viele der Standardbibliotheken passen mir nicht und habe ich desshalb durch eigene Implementationen ersetzt.
-
@Shade Of Mine
Das mit den Framezahlen habe ich mit Fraps nachgemessen um sicherzustellen, dass ich keinen Fehler in der Berechungsformel habe.
-
Ich vermute bei den Problemen mit std::vector etc. eher, dass Debugmodus und/oder checked Iterators (die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen) vermessen wurden. Gerade das "entleeren" eines std::vector sollte nichts kosten, da std::vector beim Verkleinern nicht reallokiert. Und wenn die im std::vector gespeicherten Strukturen PODs sind, findet auch kein Destruktoraufruf statt (und wenn es keine PODs sind, müssen auch die Elemente im C-Array destruiert werden).
-
Ishildur schrieb:
Diese framezahlen habe ich jetzt einfach mal ueberlesen.
Glaubst du mir etwa nicht?
Die Zahlen sind komisch. FPS ist kein sehr guter Indikator für die tatsächliche Geschwindigkeit.
Fraglich ist, wie gemessen wurde und wie relevant das Ergebnis ist. Wenn mit einer Auflösung von 1 ms gemessen wurde, kann schon ein tatsächlicher Unterschied von lediglich 0.01 ms zu so einem drastischen Sprung des angezeigten Messwerts führen. Da du ausgerechnet 1000 und 500 genannt hast, liegt es nahe, dass das hier passiert sein könnte.
Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS; auf diese realistische Frequenz umgerechnet beträgt der Unterschied nur noch ein paar Prozent. Und das auch nur, wenn tatsächlich exakt gemessen wurde, und nicht im 1 ms-Raster.
Diese paar Prozent, die nachher vielleicht gar nicht relevant sind, hast du dir durch mehr Entwicklungsaufwand erkauft. Und vielleicht mehr Debugging-Aufwand, wenn sich Fehler eingeschlichen haben die mit erprobten Strukturen nicht aufgetreten wären.LordJaxom schrieb:
Ich vermute bei den Problemen mit std::vector etc. eher, dass Debugmodus und/oder checked Iterators (die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen) vermessen wurden.
Ein sehr gern gemachter Fehler beim Messen.
-
die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen
Hoppla, ja da hatte ich tatsächlich nichts entsprechendes deaktiviert, wie mache ich denn das?
Fraglich ist, wie gemessen wurde und wie relevant das Ergebnis ist. Wenn mit einer Auflösung von 1 ms gemessen wurde, kann schon ein tatsächlicher Unterschied von lediglich 0.01 ms zu so einem drastischen Sprung des angezeigten Messwerts führen. Da du ausgerechnet 1000 und 500 genannt hast, liegt es nahe, dass das hier passiert sein könnte.
Ich benutze den QueryPerformanceCounter also nix 1ms Raster :p
Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS
Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt) 60Hz ist für das Auge durchaus vernünftig und völlig ausreichend, nicht jedoch für die Haptik, da wärend 1kHz und mehr durchaus wünschenswert...
-
Ishildur schrieb:
die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen
Hoppla, ja da hatte ich tatsächlich nichts entsprechendes deaktiviert, wie mache ich denn das?
http://msdn.microsoft.com/en-us/library/aa985965.aspx
Ishildur schrieb:
Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt)
Das ist völliger Humbug. VSync ist bei LCD immer noch nötig. Wenn die Graphikkarte mit höherer Geschwindigkeit Bilder produziert als der Bildschirm Herz hat, dann kann es immernoch zu Überlappungen kommen, weil womöglich zu dem Zeitpunkt, als sich der Bildschirm sein Bild holte, die Graphikkarte gerade in den Puffer am schreiben war.
Ishildur schrieb:
Der Punkt dabei war einfach, dass ich für die Textengine (1000fps, was du mir ja nicht glaubst) ein deferred Rendering verwende. Sprich, wenn ich SpriteBatch::DrawText aufrufe, wird noch gar nichts gezeichnet, sondern der entsprechende Text als DrawJob gespeichert. Schliesslich wird einmal pro Frame der komplette Text mit Hilfe eines einzigen Rendercalls gerendert. Dafür muss aber nach jedem Frame der std::vector der Drawjobs komplett entleert werden. Mit einem nativen c - array war dieser Enleerungsprozess jedoch hinfällig, weil ich stattdessen die DrawJobs da lasse wo sie sind und stattdessen eifach den Zeiger wieder auf das erste Element setze, so werden die alten Drawjobs nach und nach überschrieben. (Was eigentlich jedes Betriebssystem auch so macht, wird ja auch nicht jedes bit mit null überschrieben, wenn eine Datei gelöscht wird...)
Also das musst du mir jetzt nochmals genauer erklären. Wieso müsste eigentlich ein
std::vector
entleert werden, ein C Array aber nicht? Wer zwingt dich überhauptclear
aufzurufen? Abgesehen davon, dass natürlich einclear
eigentlich gar keinen Speicher freigeben würde. Das klingt für mich, dass dustd::vector
regelmässig gelöscht und neu Speicher reservieren hast lassen und dich dann darüber wunderst, wenn du dies mit einem C Array nicht machst, dass es schneller ist.Da bekommt man doch etwas Zweifel an deinen Performance-Messungen
Ishildur schrieb:
oder strings aus einem statischen memory pool aufbauen
Genau das mache ich doch??
Nein, du verwendest schlicht und einfach C Strings mit einem Memory Pool. Dabei gäbe es Möglichkeiten sowas zu kapseln. Man könnte zum Beispiel einen Memory Pool erstellen und die
std::string
von dort ihren Speicher holen lassen. Oder man erstellt Views auf den Speicher mit eigenen Klassen. Es gäbe verdammt viele Möglichkeiten sowas zu optimieren und zwar auch direkt mit der STL.Es gäbe zum Beispiel auch die Möglichkeiten den Allocator zu ändern oder man kann sich Klassen bauen, welche automatisch Speicher aus einem Memory Pool besorgen, wenn einem die Allocators zu unangenehm sind.
Ein Stichwort wäre hier zum Beispiel: Small Object Allocator.
Eine mögliche Implementation hat Andrei Alexandrescu in seinem Buch Modern C++ Design vorgestellt. Der Code ist im Internet in der Loki Bibliothek vorhanden:
http://loki-lib.sourceforge.net/
http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/SmallObj.h?view=markupDaran sieht man, was für Möglichkeiten einem offen stehen und man kann das für seine Zwecke verändern.
Genau das mache ich doch?? Ich finde C++ super, nur viele der Standardbibliotheken passen mir nicht und habe ich desshalb durch eigene Implementationen ersetzt.
Das sieht aber nicht wirklich danach aus. Es sieht mehr nach einem C mit Klassen aus. Schon nur deine C Strings deuten darauf hin, welche du nicht sinnvoll gekapselt hast. Wahrscheinlich auch an vielen Orten Dinge wie RAII missachtet, usw. usf.
Es sieht hauptsächlich danach aus, als wenn du die C++ Standardbibliothek weggeworfen hast und nun die C Bibliothek einsetzt und dies einfach in Klassen. Das ist aber kein sinnvoller und sicherer Ersatz.Für eine Korrektur ist es sicherlich zu spät, da stimme ich dir zu. Nur solltest du vielleicht aufpassen, was du in die Arbeit schreibst, wieso du so programmiert hast. Und für die Zukunft gibt es noch einiges zu lernen
Grüssli