Kommandozeilenparameter in Array speichern
-
Hmm ... naja nicht ganz richtig
std::vector<std::string> arguments(argv + 1, argv + (argc - 1));
Oder willst du den Programmpfad/namen dabei haben
-
Konrad Rudolph schrieb:
Wieso ne Deque?
Hatte ich mich anfangs auch gefragt. Die Antwort, die ich mir gegeben habe ist, dass man beim Auswerten der Optionen die bereits verarbeiteten gerne vorne rausholen möchten könnte. Praktisch um die verbliebenen Argumente dann an einen anderen Verarbeiter weiterzugeben.
(D)Evil schrieb:
Hmm ... naja nicht ganz richtig
std::vector<std::string> arguments(argv + 1, argv + (argc - 1));
Oder willst du den Programmpfad/namen dabei haben
Dann einigen wir uns aber auf diese Variante, ok?
std::vector<std::string> arguments(argv + 1, argv + argc);
-
okay
-
Konrad Rudolph schrieb:
Wieso ne Deque?
Was spricht dagegen? Ich zieh standardmaessig eine deque dem vector vor, allerdings aus Gruenden, die bei dieser speziellen Anwendung nicht ins Gewicht fallen. Ob man nun eine deque oder einen vector benutzt, duerfte vor allem mit dem von LordJaxom erwaehnten Range-Konstruktor hier voellig wurscht sein. Bei der push_back methode koennte ein vector zwischendurch umkopieren muessen, wenn die anfangskapazitaet kleiner als die Zahl der Kommandozeilenparameter ist.
-
(D)Evil schrieb:
...Oder willst du den Programmpfad/namen dabei haben
Klar - warum nicht ? Ich habe die immer mit dabei....Gruß,
Simon2.
-
Hi Pumuckl,
Ich zieh standardmaessig eine deque dem vector vor
Das halte ich für falsch. Für Anwendungen, wo nur push_back gebraucht wird, ist der Vektor schneller – immer. Und wenn man vorhersagbare Laufzeit braucht, muss man wohl oder übel die List benutzen, da auch die Deque manchmal neue Speicherblöcke anfordern muss.
Der einzige Vorteil der C++-Deque (!) in allgemeinen Anwendungen ist das schrittweise Freigeben von Speicher, was dann im Vergleich zum Vektor um einiges schneller geht.
-
Konrad Rudolph schrieb:
Das halte ich für falsch. Für Anwendungen, wo nur push_back gebraucht wird, ist der Vektor schneller – immer.
Stimmt so leider nicht. Gerade bei vielen push_back()s muss der vector immer wieder einen neuen, größeren Speicherblock allokieren und dann den gesamten Inhalt vom alten in den neuen Block kopieren. Deque hingegen allokiert sich eine neue page und lässt den alten content unangetastet. Das kann gerade bei nicht-trivialen Klassen einen enormen Overhead bedeuten. Natürlich kann man, wenn man von vornherein die Anzahl der Elemente kennt, sich mit reserve() das kopieren und neu-allikieren beim vector sparen, aber das ist dann einer der (nicht allzu häufigen) Spezialfälle wo vector das Rennen macht. Ich weiß, dass das Thema kontrovers ist, mehr dazu unter anderem hier.
-
pumuckl schrieb:
Gerade bei vielen push_back()s muss der vector immer wieder einen neuen, größeren Speicherblock allokieren und dann den gesamten Inhalt vom alten in den neuen Block kopieren.
Ich bin gerade zu faul, in eine Implementierung zu schauen. Aber wird da wirklich der Kopierkonstruktor der Elemente aufgerufen? Das wäre ja eine Verschwendung. Ich dachte bisher, das sei lediglich eine Block-Kopie. Das wäre doch vollkommen ausreichend.
Ich gehe sogar so weit zu behaupten, dass ein Vektor falsch implementiert ist, wenn er den Kopierkonstruktor beim Umräumen aufruft.
Abgesehen davon hat ein Vektor natürgemäß wesentlich bessere konstante Faktoren als die Deque (und zwar teilweise signifikant besser) für all seine Zugriffsoperationen. Ich habe neulich mal einen Performance-Test gemacht und der hat die Deque klar von den Rängen verwiesen.
Ich muss sagen, dass ich den GOTW-Artike nicht grandios finde. Die Daten sind hoffnungslos veraltet und der Artikel geht mir nicht genug in die Tiefe.
-
Ich ging bisher immer selbstverständlich davon aus und bin auch nach wie vor überzeugt davon, dass ein Vector beim Umräumen seine Elemente kopieren muss.
Und wie anders kann man C++-Objekte kopieren als mit der üblichen Kopiersemantik? Ein memcpy auf ein Array von C++-Objekten in freier Wildbahn ist tödlich, dann wird es im Vector auch nicht viel besser aussehen. Ausserdem ist Kopierbarkeit ja auch eine der Anforderungen an Vector-Elementtypen.
-
LordJaxom schrieb:
Ich ging bisher immer selbstverständlich davon aus und bin auch nach wie vor überzeugt davon, dass ein Vector beim Umräumen seine Elemente kopieren muss.
Hmm, scheint zu stimmen:
The constructor
template <class InputIterator> vector(InputIterator first, InputIterator last)
[…] does at most2N
calls to the copy constructor ofT
andlogN
reallocations … since it is impossible to determine the distance betweenfirst
andlast
and then do copying.2N ist eine obere Grenze für 1 + 2 + … + N / 4 + N / 2 + N. Demnach wird für jede Reallokation der Kopierkonstruktor aufgerufen.
-
Rohen Speicher zu kopieren ist doch archaisch, nicht umsonst ist memcpy nicht Teil der C++-Standardbibliothek sondern der C-Bibliothek
Stell dir mal eine Klasse vor, die in irgendeiner Weise einen Pointer auf ein eigenes Element enthält. Beim simplen memcpy zeigt der Pointer hinterher immernoch dorthin, wo das Element mal war. Willkommen bei den Segfaults
-
pumuckl schrieb:
Rohen Speicher zu kopieren ist doch archaisch
Nein, nur low-level.
nicht umsonst ist memcpy nicht Teil der C++-Standardbibliothek sondern der C-Bibliothek
… damit *ist* es Teil der C++-Standardbibliothek. Aber ich dachte auch eher an 'std::copy' auf einen 'std::raw_storage_iterator'.
Stell dir mal eine Klasse vor, die in irgendeiner Weise einen Pointer auf ein eigenes Element enthält.
Wer macht denn sowas? o.O
-
Naja denken wir uns doch mal eine Stringklasse, die ein Array von 50 Zeichen als Member enthält, und erst wenn der Inhalt auf mehr als 50 Zeichen anwächst einen Puffer auf dem Heap allokiert. Der Einfachheit halber wird die Adresse des aktuellen Inhalts in einem Zeiger gehalten, der entweder auf ein Member des eigenen Objekts zeigt, oder aber irgendwo in den Heap.
-
Konrad Rudolph schrieb:
LordJaxom schrieb:
Ich ging bisher immer selbstverständlich davon aus und bin auch nach wie vor überzeugt davon, dass ein Vector beim Umräumen seine Elemente kopieren muss.
Hmm, scheint zu stimmen:
The constructor
template <class InputIterator> vector(InputIterator first, InputIterator last)
[…] does at most2N
calls to the copy constructor ofT
andlogN
reallocations … since it is impossible to determine the distance betweenfirst
andlast
and then do copying.2N ist eine obere Grenze für 1 + 2 + … + N / 4 + N / 2 + N. Demnach wird für jede Reallokation der Kopierkonstruktor aufgerufen.
Wo ist das Zitat her? Es ist zweifellos richtig bei reinen Inputiteratoren, aber oft hat man es doch wenigstens mit Forwarditeratoren zu tun. Eine Implementation, die diesen Fall nicht ausnutzt und die Länge der Sequenz nicht ermittelt, kann getrost als unbrauchbar bezeichnet werden. Zudem trifft obige Berechnung nur zu, wenn vector die Größe jeweils verdoppelt. Das muss er nicht, ein anderer Faktor ist absolut möglich.
-
Konrad Rudolph schrieb:
Wer macht denn sowas? o.O
Kommt bestimmt mal vor... ich könnt mir vorstellen, dass man sowas bei manchen Policies brauchen kann, wenn man die Policy nicht sauber vom eigentlichen Objekt trennen kann.
template <class Policy> class Foo : private Policy { public: Foo() : Policy(this) {} /* ... */ }; struct WeirdFooPolicy { WeirdFooPolicy(Foo* mymaster) : mymaster_(mymaster) {}; Foo* mymaster_; };
Memcpy() das mal, dann zeigt die Policy nach wie vor dahin wo foo mal war
Konrad Rudolph schrieb:
nicht umsonst ist memcpy nicht Teil der C++-Standardbibliothek sondern der C-Bibliothek
… damit *ist* es Teil der C++-Standardbibliothek.
Dachte immer das würde differenzierter behandelt oO
-
LordJaxom schrieb:
Naja denken wir uns doch mal eine Stringklasse, die ein Array von 50 Zeichen als Member enthält, und ...
Ist gar nicht so hypothetisch: Das Thema kommt doch einmal im Monat hier auf, wenn wieder jemand versucht, einen std::string per binärem fwrite() wegzuschreiben ("Warum schneidet fwrite() nach dem 50. Zeichen ab ?")...
Gruß,
Simon2.
-
Gut, ihr habt mich überzeugt.
-
Ui hat das eine Diskussion ausgelöst ...
Naja, ich habe ein weiteres Problemchen, ich würde gerne die Länge bestimmen von der 2. Dimension.
In einem normalen Char-Array kann man ja praktischerweise mittels strlen(array) die Anzahl der Elemente ermitteln, aber wie funktioniert das im mehrdimensionalen Bereich? Hierbei interessiert mich eigentlich nur die Anzahl der Elemente aus der zweiten Ebene, also array[1][x].Ich hoffe mir kann jemand helfen, ich finde nicht wirklich eine Lösung, weder durch Ausprobieren, noch durch Suchmaschine.
MfG
edit: Ich glaube, ich habe es selbst gerade herausgefunden:
cout << strlen(array[1]) << endl;
-
Hi,
eigentlich kannst Du die Länge überhaupt nicht ermitteln. Du kannst nur solange im Speicher suchen, bis Du ein '\0' findest und hoffen, dass es das Ende Deines Strings markiert (anderes macht ja strlen() auch nicht).
Nochmal : Nimm std::string !
Selbst bei den "0-terminierten Strings" (NTBS) musst Du Dir ja (wenn Du sauber programmieren möchtest) mindestens die Länge des char-Arrays merken (damit Du nicht über diesen Bereich hinaus schreibst/liest). Lokal kannst Du Dir noch mit sizeof() behelfen, aber früher oder später willst Du das Teil auch einer Funktion übergeben und da klappt das nicht mehr (auch die str-/printf-Funktionen sind in dieser Hinsicht unsicher - wenn schon, dann die strn-/nprintf-Varianten nehmen !).
Dann kannst du dir auch gleich die Länge der Zeichenkette merken.Und schließlich musst du dir bei jedem Schritt überlegen, was denn passieren soll, wenn für eine Schreibaktion (insert/copy) nicht mehr genug Platz bereitsteht ...
All das nimmt dir std::string hinter den Kulissen ab und ist nicht weniger mächtig aber viiiiiiel komfortabler und übersichtlicher.
Gruß,
Simon2.