Ich habe in letzter Zeit einige notwendige Optimierungen vorgenommen. Eine Sache, die ich getan habe, ist, einige Ostringströme zu verändern -> Sprintfs. Ich sprinte ein paar Standard-Strings zu einem Array im Stil von AC, ala
char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());
Es stellt sich heraus, dass die Implementierung von Microsoft std :: string :: c_str () in konstanter Zeit ausgeführt wird (es wird nur ein interner Zeiger zurückgegeben). Es scheint, dass libstdc ++ dasselbe tut . Ich verstehe, dass der Standard keine Garantie für c_str gibt, aber es ist schwer, sich eine andere Art und Weise vorzustellen, dies zu tun. Wenn sie zum Beispiel in den Speicher kopiert werden, müssen sie entweder Speicher für einen Puffer zuweisen (es bleibt dem Aufrufer überlassen, ihn zu zerstören - NICHT Teil des STL-Vertrags) ODER sie müssen in eine interne statische Datei kopieren Puffer (wahrscheinlich nicht threadsicher, und Sie haben keine Garantie für seine Lebensdauer). Es scheint also die einzig realistische Lösung zu sein, einfach einen Zeiger auf eine intern gepflegte nullterminierte Zeichenfolge zurückzugeben.
quelle
c_str
es sich um eine const-Methode handelt (oder zumindest eine const-Überladung hat - ich vergesse welche), ändert dies den logischen Wert nicht und kann daher ein Grund dafür seinmutable
. Es würde Zeiger von anderen Aufrufen auf unterbrechenc_str
, mit der Ausnahme, dass sich solche Zeiger auf dieselbe logische Zeichenfolge beziehen müssen (es gibt also keinen neuen Grund für eine Neuzuweisung - es muss bereits ein Nullterminator vorhanden sein), oder es muss bereits ein Aufruf an einen Nicht-Benutzer stattgefunden haben -const Methode dazwischen.c_str
Anrufe O (n) Zeit für die Neuzuweisung und das Kopieren sein. Es ist aber auch möglich, dass der Standard zusätzliche Regeln enthält, von denen ich nicht weiß, dass sie dies verhindern würden. Der Grund , warum ich es vorschlagen - Anrufec_str
sind nicht wirklich gemeint AFAIK üblich sein, so ist es nicht wichtig , in Betracht gezogen werden kann sie schnell , um sicherzustellen , - dass zusätzliche Byte Speicherplatz für einen normalerweise unnötigen Nullabschluss bei der Vermeidung vonstring
Fällen , die nie Gebrauchc_str
kann Vorrang haben.Boost.Format
Intern durchläuft Streams, die intern einensprintf
ziemlich hohen Overhead verursachen. Die Dokumentation sagt, es ist ungefähr 8-mal langsamer als normalsprintf
. Wenn Sie Leistung und Typensicherheit wünschen, versuchen Sie esBoost.Spirit.Karma
.Boost.Spirit.Karma
Dies ist ein guter Tipp für die Leistung, aber beachten Sie, dass es eine völlig andere Methodik gibt, die es schwierig machen kann, vorhandenenprintf
Style-Code (und Codierer) anzupassen . Ich habe mich weitgehend daran gehalten,Boost.Format
weil unser I / O asynchron ist. Aber ein großer Faktor ist, dass ich meine Kollegen davon überzeugen kann, es konsequent zu verwenden (erlaubt immer noch jeden Typ mit einerostream<<
Überlastung - was die.c_str()
Debatte angenehm umgeht ). Die Karma-Leistungszahlen .Im c ++ 11-Standard (ich lese die Version N 3290) wird in Kapitel 21.4.7.1 die Methode c_str () beschrieben:
const charT* c_str() const noexcept; const charT* data() const noexcept;
Also ja: Die konstante zeitliche Komplexität wird durch den Standard garantiert.
Ich habe gerade den c ++ 03-Standard überprüft, und er hat weder solche Anforderungen noch zeigt er die Komplexität.
quelle
Theoretisch erfordert C ++ 03 dies nicht, und daher kann der String ein Array von Zeichen sein, bei dem das Vorhandensein des Nullterminators nur zum Zeitpunkt des Aufrufs von c_str () hinzugefügt wird. Dies kann eine Neuzuweisung erforderlich machen (verstößt nicht gegen die Konstanz, wenn der interne private Zeiger als deklariert ist
mutable
).C ++ 11 ist strenger: Es erfordert Zeitaufwand, sodass keine Verlagerung durchgeführt werden kann und das Array immer breit genug sein muss, um die Null am Ende zu speichern. c_str () selbst kann immer noch "
ptr[size()]='\0'
" sicherstellen, dass die Null wirklich vorhanden ist. Dies verletzt nicht die Konstanz des Arrays, da der Bereich[0..size())
nicht geändert wird.quelle