Nutzung der STL in Firmen. Ist die STL schlimm?
-
Keine aktuelle std::string Implementierung wird COW verwenden, da dies spätestens seit C++11 afaik nichtmehr erlaubt ist.
Auch STL Impls vor c++11 haben kaum Cow optimiert.
Das interface laesst es zu, aber die Laufzeitzusagen der SGI Spec nicht.std::string s1 = "123456"
std::string s2 = s1;s2[2] = '9'; /// bei Cow wuerde hier das kopieren stattfinden. IMHO Laut SGI Spec sollte der zugriff aber in fester Zeit ablaufen, und nicht von der Lange des Strings und dem zustand des BS abhaengen.
Die ersten versionen der Dinkumware STL habens damit versucht und gab wohl erwartet massive probleme besonders bei Multithreading. Dann gabs Teilweisse unterschiedliche implementierungen für ST und MT .... und irgendwann (VS6.0 zeitraum) nur noch die variante ohne cow otimierung.
Bei *nixern bin ich mir ned sicher, aber einige gcc Anwender behaupten felsenfest, das ihre STL cow optimiert .... keine Ahnung ob das stimmt.
Wofür also überhaupt erst eine Liste machen
Ich krieg oft interfaces vorgesetzt, wo ich Listen befüllen muss. Meist direct zu anzeigezwecken für ein Modell.
Oder wie würdest du Liste von strings durch ein Interface schiessen, wenn das ";" da drinne implementierungsdetail ist und nicht in die GUI Schicht gehört ?
und templates(iteratoren) in interfaces auch nicht das wahre sind ....std::unordered_map
C11 darf ich leider nicht verwenden ^^ mein code muss z.b. mit vs2005 kompilierbar sein ^^ Klingt doof, ich finds auch doof, iss aber so ^^
Und nein ich kanns ned in ne dll auslagern, dann haut mich der Distributor unserer SW ^^Finde ich nicht. split() lässt sich, wie oben angeführt, aus Prinzip nicht effizient implementieren und ist auch völlig unnötig,
unnötig finde ich es nicht ....
Ja generell wenn man performant entwickelt wird man split meiden ....
Aber GUI eintwicklung und Bibliotheksentwicklung sind IMHO 2 paar schuhe ...
In ner GUI lass ich viele Bereiche unoptimiert, weils keinen Intressiert, und ich eher dafür angefahren werde, wenn ich da zeit und energie verheize.
Da will ich lieber einfachen naiv lesbaren code (wartung).
Bei ner lib weiss ich ned wer was wie verwendet, da versuch ich am anfang schon vernuenftig performant zu entwickeln, auch wenns da bissi laenger dauert. Da krieg ich auch ned so viel Ärger, da hat mans lieber wenn die lib von haus aus gut funktioniert.Deswegen:
In der Qt ist split ok,
in der stl hat IMHO ein naives
std::list<std::basic_string<T> > std::basic_string::split(value_type sep);
nichts zu suchen. Weil es zu generisch und ineffizent ist.
Man wird in der Praxis mit der STL definierte Rahmenbedingungen haben und anderes verwenden ...Ciao ...
-
RHBaum schrieb:
Keine aktuelle std::string Implementierung wird COW verwenden, da dies spätestens seit C++11 afaik nichtmehr erlaubt ist.
Auch STL Impls vor c++11 haben kaum Cow optimiert.
Es ist legitim zu fragen, wozu es std::string braucht, wenn es schon std::vector<char> gibt. std::string mit COW ist perfekt geeignet für Datenstrukturen, die zwar eine Referenz auf einen string brauchen, aber ihn nicht kopieren möchten (die unsicherere Variante wäre const char*). Wozu man massig std::strings verändern will ist mir sowieso nicht klar.
Ich würde sagen für single-threaded Anwendungen wäre ein std::string, bei dem COW vorgeschrieben ist besser als ein std::string, bei dem COW verboten ist.
RHBaum schrieb:
Das interface laesst es zu, aber die Laufzeitzusagen der SGI Spec nicht.
std::string s1 = "123456"
std::string s2 = s1;s2[2] = '9'; /// bei Cow wuerde hier das kopieren stattfinden. IMHO Laut SGI Spec sollte der zugriff aber in fester Zeit ablaufen, und nicht von der Lange des Strings und dem zustand des BS abhaengen.
Der Zugriff ist immer noch amortisiert konstant. Entweder zahlst du bei der Kopie oder beim Zugriff, ist doch wurst wo.
gab wohl erwartet massive probleme besonders bei Multithreading.
massiv ist übertrieben. Ist halt langsam.
Bei *nixern bin ich mir ned sicher, aber einige gcc Anwender behaupten felsenfest, das ihre STL cow optimiert .... keine Ahnung ob das stimmt.
Jo, stimmt und die Standardbibliothek des GCCs macht das immer noch so um die Binärschnittstelle kompatibel zu halten. Soll sich aber demnächst ändern (clangs libc++ macht das schon richtig).
Finde ich nicht. split() lässt sich, wie oben angeführt, aus Prinzip nicht effizient implementieren und ist auch völlig unnötig,
unnötig finde ich es nicht ....
Ja generell wenn man performant entwickelt wird man split meiden ....Wo ist das Problem?
Ein
for (string_ref s : split(s.begin(), s.end(), ';'))lässt sich schön lazy ohne zusätzliche Kopien lösen.
std::list<std::basic_string<T> > std::basic_string::split(value_type sep);
[...] Weil es zu generisch und ineffizent ist.lol ja, std::list ist sehr ineffizient.
-
Nexus schrieb:
std::string t = "text"; std::string r = t + " und " + "mehr " + t;Wie viele temporäre Objekte hast du hier?
Mal sehen...
((t + " und ") + "mehr ") + t // => operator+(operator+(operator+(t, " und "), "mehr "), t)Und jetzt die Operatoren aus den MinGW-4.8.1 Headern
template<typename _CharT, typename _Traits, typename _Alloc> inline basic_string<_CharT, _Traits, _Alloc> operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs, const _CharT* __rhs) { basic_string<_CharT, _Traits, _Alloc> __str(__lhs); __str.append(__rhs); return __str; // NRVO greift, §12.8/31 } template<typename _CharT, typename _Traits, typename _Alloc> inline basic_string<_CharT, _Traits, _Alloc> operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs, const _CharT* __rhs) { return std::move(__lhs.append(__rhs)); } template<typename _CharT, typename _Traits, typename _Alloc> inline basic_string<_CharT, _Traits, _Alloc> operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs) { return std::move(__lhs.append(__rhs)); }Ich bin mir hier überhaupt nicht sicher, würde aber sagen, dass es zwei temporäre Objekte gibt.
-
Arcoth schrieb:
[/code]Ich bin mir hier überhaupt nicht sicher, würde aber sagen, dass es zwei temporäre Objekte gibt.
Ich würde behaupten, dass der Aufwand äquivalent zu 3 temporaries ist. Append wird wahrscheinlich neuen Speicher anfordern müssen und dafür den String umkopieren. Das ist am Ende so teuer wie ein temporary.
//edit eigentlich ginge es mit nur einem temporary. Aber der Standard legt die Signatur von operator+ fest, von daher geht da nichts besseres. Sonst könnte man ein expression template basteln, welches dann einen stringbuilder emuliert.
-
Append wird wahrscheinlich neuen Speicher anfordern müssen und dafür den String umkopieren.
Hast Recht, soweit ich es vom groben drüberschauen richtig interpretiere
template<typename _CharT, typename _Traits, typename _Alloc> basic_string<_CharT, _Traits, _Alloc>& basic_string<_CharT, _Traits, _Alloc>:: append(const _CharT* __s, size_type __n) { __glibcxx_requires_string_len(__s, __n); if (__n) { _M_check_length(size_type(0), __n, "basic_string::append"); const size_type __len = __n + this->size(); if (__len > this->capacity() || _M_rep()->_M_is_shared()) { if (_M_disjunct(__s)) this->reserve(__len); // Speicher-Anforderung else { const size_type __off = __s - _M_data(); this->reserve(__len); // dito __s = _M_data() + __off; } } _M_copy(_M_data() + this->size(), __s, __n); // Kopie _M_rep()->_M_set_length_and_sharable(__len); } return *this; }Sonst könnte man ein expression template basteln, welches dann einen stringbuilder emuliert.
So etwas ginge mit Boost.Proto, nicht wahr? Ist den das drumherum des expression template frameworks schnell genug, dass dabei etwas herausspringt?
-
Man könnte auch ne eigene String-Builder Klasse machen.
Oder nen Stringstream nehmen (der hoffentlich darauf optimiert ist schnell zu sein, und dafür ordentlich grosse Stücke Speicher anfordert).
Oder man könnte ne Spracherweiterung machen: Overloads für Fälle wo der Returnwert in ein temporäres Objekt reinkonstruiert wird.
Diese Overloads könnten dann auch gleich ordentlich overcommitten - da das erzeugte Objekt eh gleich wieder stirbt. Und wenn es vor seinem Tod noch über Move "ausgeschlachtet" wird, dann hätte der ausschlachtende operator + gleich nen grösseren Puffer mit dem er arbeiten kann.Natürlich müsste dieser operator +, falls sein Ergebnis nicht in einem Temporary landet den viel-zu-grossen Puffer wieder zusammenstutzen. Was in gewissen Fällen vermutlich zu einer Verschlechterung führen würde.
Und man könnte Probleme mit breiten (viele Parameter) und/oder sehr "tief gehenden" rekursiven Aufrufen bekommen. Da bei diesen halt dummerweise doch sehr viele Temporaries gleichzeitig existieren.@knivil
Für reserve musst du erstmal wissen wie lange der String werden wird. Wird er nämlich länger, dann greift wieder die meist eher sparsam ausgelegte Reallocation-Strategie vonstd::string=> unpraktisch.Und
std::vector<char>ist fein. Nur dummerweise kein String-Builder.
std::stringstreamwäre eher der C++ String-Builder.
Wobei ich keine Benchmarks zu dem Thema kenne. Sobald man aufstd::ostringstreamLocale-abhängige Sachen macht ist er recht langsam. Wie die Performance ist wenn man nur Strings reinschiebt weiss ich nicht.Nur ist das alles irgendwie nicht so richtig handlich.
Foo(s + "foo" + s2 + Bar(1, 2, 3)); // :-) Foo(static_cast<stringstream&>(stringstream() << s << "foo" << s2 << Bar(1, 2, 3)).str()); // Pffffff... Foo(stringbuilder() + s + "foo" + s2 + Bar(1, 2, 3)); // Immer noch nicht toll, aber eine implizite Konvertierung // nach std::string wäre ein Schritt in die richtige Richtung. // Oder... Foo(concat(s, "foo", s2, Bar(1, 2, 3))); // Hmmmm... kurz isses ja, aber irgendwie... hmmm... gefällt mir nicht so.
-
Es ist legitim zu fragen, wozu es std::string braucht
std::vector vs. std::string
Ich find vector in anderen dingen unhandlicher.
ist man mal auf std::string ebene, heissen die funktionen zum manipulieren halt auch stringlike, das liest sich einfach besser.
und das concatenieren geht halt nativ ....
beim vector muss man da mehr rumdoctoren und immer auf das abschliesende '\0' achten. meist braucht man ja c strings kompatiblitaet um andere libs anzusteuern.Wozu man massig std::strings verändern will ist mir sowieso nicht klar.
bei mir iss das täglich Brot ^^
Ich mach z.b. so was aehnliches wie der Wireshark macht, nur fuer andere "Busse" und komplett andere protokolle.
Und ich muss aus "telegrammen" (bytefolgen) menschenlesbare zeichenkettenproduzieren.
Sowas wie z.b. "Temperatursensor T12 108,57 °C"
Die "stringvorlagen" kommen aus nem xml aus nem Parser, der std::strings liefert.
Ich selber verwend aber relativ oft auch std::vector (C-String in nem Buffer) aus performancegründen.
aber mein zeugs iss auch gut gekapselt ^^die Busse schaffen bis zu 100Mbit/s was bei dem speziellen ~75Mbit/s Nutzdaten sind.
Interpretieren (plausibilitaets checks und flags errechnen etc.) tu ich alles, die strings erzeug ich nur auf Bedarf.
Am ende siehts aus ähnlich wie beim wireshark so ne aktualisierende Liste(das machen die GUI typen) ich muss nur die strings entsprechend schnell liefern, sonst stockts ^^
-
Foo((stringstream() << s << "foo" << s2 << Bar(1, 2, 3)).str());
Sowieso ill-formed. Da gehoert noch ein Cast hinzu.
Laesst sich aber bestimmt leicht fixen.
-
STLOderWas schrieb:
Hallo,
ich hatte in letzter Zeit mehrere Vorstellungsgespraeche bei Softwarefirmen (bunt gemixt, Spielefirmen, etc.).
In den Gesprachen habe ich immer gesagt ich versuche wo es nur geht die STL und Boost zu benutzen. Fast jedes mal bekam ich die Antwort, "STL/Boost benutzen wir nicht, wir haben unsere eigenen Container usw.".
Wenn ich das hoere laeuft es mir immer kalt den Rucken runter. Im Studium habe ich selbst vectoren usw. implementiert um zu wissen wie es funktioniert. Aber ich wuerde nie auf die Idee kommen einen Container usw. fuer die Entwicklung zu schreiben. Ich mag C++ sehr und habe schon viele Programme geschrieben (nur Forschung oder Hobby) bisher konnte ich mich nie ueber die STL beklagen. Oft schaue ich mir auf youtube Konferenzbeitraege (Going Native etc.) an. Ich verstehe viele Sachen in C++ noch nicht und werde viele Sachen wahrscheinlich auch nie richtig verstehen. Aber ich denke die STL ist wirklich von Leuten geschrieben die C++ wirklich zu 100% verstehen und sie liefert fuer fast alle Arten von Programmen eine sehr gute Performance.
Ich habe nicht in grossen Firmen gearbeitet und ich will es mir nicht anmassen ueber Software zu urteilen an der ich nicht mirgearbeitet habe. Aber wenn ich die Leute im Vorstellungsgespraech so reden hoere habe ich das Gefuehl die STL hat keinen Wert.
Wie ist eure Meinung dazu?
mfg

Das "not invented here"-Symptom taucht in vielen Firmen auf. Man setzt oft auf eigene Bibliotheken, weil man dabei jeden Aspekt unter Kontrolle hat. Die STL, obwohl integraler Bestandteil von C++, wird häufig verschmäht. Vielleicht traut man Templates nicht, oder scheut die nötige Einarbeitungszeit. In Bereichen mit beschränkten Hardwareressourcen wird oft nur das C in C++ benutzt.
-
Arcoth schrieb:
Foo((stringstream() << s << "foo" << s2 << Bar(1, 2, 3)).str());
Sowieso ill-formed. Da gehoert noch ein Cast hinzu.
Laesst sich aber bestimmt leicht fixen.Wo soll da bitte ein Cast fehlen?
Und schreib das nächstes mal bloss nicht gleich dazu.
-
hustbaer schrieb:
Arcoth schrieb:
Foo((stringstream() << s << "foo" << s2 << Bar(1, 2, 3)).str());
Sowieso ill-formed. Da gehoert noch ein Cast hinzu.
Laesst sich aber bestimmt leicht fixen.Wo soll da bitte ein Cast fehlen?
operator << liefert einen std::ostream& zurück. std::ostream hat keine methode str()...

-
Hmpf.
Ich mach das normalerweise nur mit boost::format(). Und da funktioniert es. Ich weiss schon warum ich die C++ IO-Streams nicht mag.
-
dot schrieb:
operator << liefert einen std::ostream& zurück. std::ostream hat keine methode str()...

Aus welchem Grund gibt operator<<(std::ostringstream&,value) keinen ostringstream zurück?
-
ostream.str schrieb:
dot schrieb:
operator << liefert einen std::ostream& zurück. std::ostream hat keine methode str()...

Aus welchem Grund gibt operator<<(std::ostringstream&,value) keinen ostringstream zurück?
Weil es keinen operator<<(std::ostringstream&,value) gibt, sondern nur einen operator<<(std::ostream&,value)
wäre sonst ja doof wenn du einen eigenen op<< für deine Klasse anbieten wollen würdest und dann diese für alle unterschiedlichen ostream subklassen überladen müsstest

-
Und schreib das nächstes mal bloss nicht gleich dazu.
Was meinst du damit?

-
Arcoth schrieb:
Und schreib das nächstes mal bloss nicht gleich dazu.
Was meinst du damit?

"Schreib es nächstes Mal dazu."
-
@dot
Danke.
Hab's ausgebessert (ich hoffe ich hab' nicht wieder was übersehen).@Arcoth
Ja, ich meine: schreib' es das nächste mal bitte dazu.
Ich geb' ja zu, den Fehler hätte ich selbst finden können. Aber ... manchmal denkt man halt nicht an alles.@Shade Of Mine
Mit nem leicht modifizierten Design hätte man es darauf beschränken können dass jeder Stream die Operatoren neu definieren muss (operator << ruft freie "insert_to_stream" Funktion auf, und diese wird von den Value-Typen überladen - das "return *this" stünde dann natürlich im operator << und nicht in der Hilfsfunktion).Und mit C++11 müsste es sogar ohne eine eigene Funktion pro Stream gehen. Stream-Typ als Template-Parameter der mittels enable_if auf Stream-Typen eingeschränkt ist.
Aber jetzt kann mans natürlich nimmer so leicht ändern.
-
hustbaer schrieb:
Aber jetzt kann mans natürlich nimmer so leicht ändern.
Auch eines der Gründe, nicht die STL nutzen zu wollen.
Wenn das Design in irgendeiner Komponente - sagen wir mal, nicht ganz ausgereift ist - wird das vermutlich für immer so bleiben. Will man es nicht, braucht man Alternativen bzw. implementiert eine eigene.**Wobei man natürlich bei der Implementierung der eigenen auf die STL zugreifen kann.
-
Der * ist der Knackpunkt

(Zu) viele Programmierer sehen das nämlich anders. Und implementieren in ihrer Wut und Raserei dann (ohne guten Grund) alles selbst.
(Wobei ich nochmal darauf hinweisen möchte dass ich durchaus der Meinung bin dass es gute Gründe gibt. Nur dass die meisten die meinen sie hätten so einen guten Grund eben doch keinen haben.)