C ++ map & lt; std :: string & gt; vs Karte & lt; char * & gt; Leistung (ich weiß, "wieder?")
War ich mit einer Karte mit einem std::string
- Taste und während alles gut funktioniert, ich war nicht immer die Leistung, die ich erwartet hatte. Ich habe nach Orten gesucht, um zu optimieren und verbessert die Dinge nur ein wenig und das ist, wenn ein Kollege sagte:", string key wird langsam sein."
Las ich Dutzende von Fragen, und Sie konsequent zu sagen:
"nicht mit einem
char *
als Schlüssel"
"std::string
Schlüssel werden nie Ihren Engpass"
"der performance-Unterschied zwischen einemchar *
und ein
std::string
ist ein Mythos."
Ich widerwillig versuchte ein char *
Schlüssel und es war ein Unterschied, ein großer Unterschied.
Ich kochte das problem auf ein einfaches Beispiel:
#include <stdio.h>
#include <stdlib.h>
#include <map>
#ifdef USE_STRING
#include <string>
typedef std::map<std::string, int> Map;
#else
#include <string.h>
struct char_cmp {
bool operator () (const char *a,const char *b) const
{
return strcmp(a,b)<0;
}
};
typedef std::map<const char *, int, char_cmp> Map;
#endif
Map m;
bool test(const char *s)
{
Map::iterator it = m.find(s);
return it != m.end();
}
int main(int argc, char *argv[])
{
m.insert( Map::value_type("hello", 42) );
const int lcount = atoi(argv[1]);
for (int i=0 ; i<lcount ; i++) test("hello");
}
Ersten std::string version:
$ g++ -O3 -o test test.cpp -DUSE_STRING
$ time ./test 20000000
real 0m1.893s
Neben der 'char *' - version:
g++ -O3 -o test test.cpp
$ time ./test 20000000
real 0m0.465s
Dass ist eine ziemlich große performance-Unterschied und zu den gleichen Unterschied, den ich in meinem größeren Programm.
Mit einem char *
Schlüssel ist ein Schmerz zu behandeln und befreien den Schlüssel und fühlt sich einfach nicht richtig. C++ Experten was bin ich? Irgendwelche Gedanken oder Anregungen?
InformationsquelleAutor der Frage uroc | 2012-08-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie mit einem
const char *
als lookup-Schlüssel fürfind()
. Für die Karte mitconst char*
dies ist die richtige Art, diefind
erwartet, und die Suche kann durchgeführt werden direkt.Die Karte mit
std::string
erwartet, dass die parameter derfind()
einestd::string
also in diesem Fall dieconst char*
muss zuerst umgewandelt werden in einstd::string
. Das ist wahrscheinlich der Unterschied, den Sie sehen.InformationsquelleAutor der Antwort sth
Als sth festgestellt, das Problem ist eine der Spezifikationen, die der assoziativen Container (sets und Karten), dass Ihr Mitglied, der Suche nach Methoden immer erzwingen, dass die Umstellung auf die
key_type
werden, selbst wenn einoperator<
vorhanden ist, würde akzeptieren, vergleichen Sie Ihren Schlüssel gegen den Schlüssel in die Karte trotz Ihrer verschiedenen Arten.Auf der anderen Seite, die Funktionen in
<algorithm>
nicht darunter leiden, zum Beispiellower_bound
ist definiert als:So, eine alternative könnte sein:
Und dann könnten Sie tun:
Wo
CompareFirst
ist definiert als:Oder sogar bauen eine komplett benutzerdefinierte Komparator - (aber es ist ein bisschen schwieriger).
Einen
vector
paar ist in der Regel effizienter Lesen-schwere Lasten, also es ist echt zum speichern einer Konfiguration zum Beispiel.Ich nicht beraten, um Methoden zu wickeln Sie die Zugriffe.
lower_bound
ist ziemlich low-level.InformationsquelleAutor der Antwort Matthieu M.
Wenn Ihr in C++ 11, der copy-Konstruktor wird nicht aufgerufen es sei denn, der string wird geändert. Weil std::string ist ein C++ - Konstrukt, das mindestens 1 dereferenzieren notwendig ist, um an die Daten der Zeichenfolge.
Meine Vermutung wäre die Zeit, in der eine zusätzliche Dereferenzierung (wenn man es 10000 mal ist teuer), und std::string dürfte dabei entsprechende null-pointer-checks, die wieder frisst Zyklen.
InformationsquelleAutor der Antwort sevensevens
Nach der Kompilierung die 2 "Hallo" string-Literale haben die gleiche memory-Adresse. Auf der
char *
wenn Sie diese Speicher-Adressen als Schlüssel.In der
string
Fall alle "Hallo"s umgewandelt werden, um ein anderes Objekt. Dies ist ein kleiner Teil (wirklich sehr klein) Ihrer performance-Unterschied.Einen größeren Teil werden kann, als alle "Hallo"s, die Sie verwenden den gleichen Speicher-Adresse
strcmp
immer 2-äquivalent-char-Zeiger und ich bin mir ziemlich sicher, dass es in der frühen prüft für diesen Fall 🙂 So wird es nie wirklich umzusetzen, die alle Zeichen, aber die std::string-Vergleich wird.InformationsquelleAutor der Antwort QwerJoe
Speichern std::string als Zeiger und dann verlieren Sie den copy-Konstruktor overhead.
Aber nachdem Sie haben, zu erinnern, zu behandeln, der löscht.
Der Grund, std::string ist langsam, baut sich. Ruft den copy-Konstruktor, und dann am Ende Anrufe löschen. Wenn Sie den string auf den heap verlieren Sie die copy-Konstruktion.
InformationsquelleAutor der Antwort Adrian Cornish