C++ Lernen - Verständnisfragen
-
@wob Müsste nicht inzwischen sowas gehen:
auto [begin, end] = std::ranges::remove_if(foobar, hastToBeDeleted); foobar.erase(begin, end);
Edit: Code angepasst... erase hat gefehlt. Macht es so nicht viel besser.
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
@wob Müsste nicht inzwischen sowas gehen:
auto [begin, end] = std::ranges::remove_if(foobar, hastToBeDeleted); foobar.erase(begin, end);
Edit: Code angepasst... erase hat gefehlt. Macht es so nicht viel besser.
Nicht in jedem fall da hier eine range erwartet wird.
Aber im folgenden falle nicht
vector enthält folgende werte1, 9, 5, 10
hastToBeDeleted hat die Bedingung <value> <= 5
Dann würde std::ranges::remove_if(foobar, hastToBeDeleted); wohl nach dem es auf den wert 9 trifft abbrechen. Und Dadurch würde der Wert 5 nicht gelöscht werden
Oder im schlimmsten falle würde die 9 auch mit gelöscht werden.
-
@firefly Nö, warum: https://godbolt.org/z/fv8G9sf7M
std::ranges::remove_if
verschiebt die Elemente so, dass die Elemente, die nicht gelöscht werden am Anfang des Ranges stehen und die, die gelöscht werden am Ende. Und zurück gegeben wird die Subrange der zu löschenden Elemente.
-
@firefly sagte in C++ Lernen - Verständnisfragen:
Dann würde std::ranges::remove_if(foobar, hastToBeDeleted); wohl nach dem es auf den wert 9 trifft abbrechen. Und Dadurch würde der Wert 5 nicht gelöscht werden
Oder im schlimmsten falle würde die 9 auch mit gelöscht werden.Nein, das erase-remove-Idiom ist nicht umsonst ein Idiom (sogar mit einenem Wikipedia-Artikel). Es wäre kein Idiom, wenn solche komischen Dinge passieren würden (wie es funktioniert, hat @Schlangenmensch ja schon geschrieben)
Edit: und lesen lohnt sich sogar, denn dann erfährt man z.B., dass es mit C++20 auch via std::erase / std::erase_if ginge.
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
@firefly Nö, warum: https://godbolt.org/z/fv8G9sf7M
std::ranges::remove_if
verschiebt die Elemente so, dass die Elemente, die nicht gelöscht werden am Anfang des Ranges stehen und die, die gelöscht werden am Ende. Und zurück gegeben wird die Subrange der zu löschenden Elemente.Ah ok hab das in der beschreibung überlesen. https://en.cppreference.com/w/cpp/algorithm/ranges/remove
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
@wob Müsste nicht inzwischen sowas gehen:
auto [begin, end] = std::ranges::remove_if(foobar, hastToBeDeleted); foobar.erase(begin, end);
Edit: Code angepasst... erase hat gefehlt. Macht es so nicht viel besser.
Und wo lliegt hier der große Vorteil? Ist doch auch nicht wirklich kürzer als das alte Idiom und macht vom Prinzip her dasselbe.
-
@Tyrdal Ich hatte im Kopf, dass es mit der Ranges lib auch in einem Aufruf hätte gehen müssen, ohne dass man den, von @wob erwähnten
end()
Aufruf vergessen kann. Hatte mich da aber im ersten Schuss vertan, daher der Edit. Die von @wob verlinktenstd::erase
undstd::erase_if
sind die schöneren Alternativen.
-
Hahah geil wir ihr alle gleich abgeht ^^
Vieles von dem was ihr geschrieben habt ist mir noch etwas zu hoch, auch wenn ich den Ansatz meist irgendwie nachvollziehen kann.Es ist interessant zu sehen welche unterschiedlichen Ansichten und Wege es für ein und das selbe Problem und dessen Lösung gibt.
Wenn ich das richtig sehe geht es bei eurer Diskusion dabei aber tendenziell um die Zuverlässigkeit des Codes und um die Geschwindigkeit - sowohl beim Code schreiben als auch beim Ausführen von diesem?!
-
Weitere Frage: Wenn ich
string::npos;
in eine Variable packen will, was ist der dafür geeignete Datentyp? Es funktioniert bei mirint
,char
,double
,float
.
Der Datentypbool
setzt dieif
Abfrage auf unwahr und gibt als Position: 18446744073709551615 aus .string satz{"Das ist ein Satz"}; string::size_type pos; int str_npos = string::npos; // Hier mit Integer cout << "'wird'"; pos = satz.find("wird"); if (pos == str_npos) cout << " nicht gefunden" << endl; else cout << "gefunden an Pos." << pos << endl;
Ob das Sinn macht oder nicht möchte ich mal außen vor lassen...
Gebe ich str_npos aus so erhalte ich :
cout << str_npos << endl;
- Als Interger = -1
- Als Double und float = 1.84467e+19
- Als Char = bleibt leer
- Als Bool = 1
Ich gehe also davon aus das der Integer am meisten Sinn macht. Da int -1 ist und damit nicht im String liegen kann. Also könnte ich ja nach meinem kümmerlichen Verständnis auch
if (pos == -1)
prüfen? Was auch funktioniert...Übersehe ich da was?
-
@Drgreentom sagte in C++ Lernen - Verständnisfragen:
Übersehe ich da was?
Ja, tust du.
std::string::npos
ist einsize_t
.size_t
ist ein unsigned Datentyp undnpos
ist der größte Wert, der damit darstellbar ist. Das dies alsint
interpretiert-1
ist, ist nirgends garantiert.
Fürbool
gilt, jeder Zahlenwert ungleich Null wird als wahr interpretiert.Daher, aufpassen, wenn Typen konvertiert werden.
std::string::size_type
garantiert, dass der Typ groß genug ist, um die Größe des Strings wiederzugeben.std::string::find
gibt einensize_t
zurück.size_t
garantiert, dass es die maximale Größe eines Objektes speichern kann.Ich bin mir gerade nicht sicher, ob
std::string::size_type
immer einsize_t
sein muss, halte es aber für wahrscheinlich, dass es in den meisten Implementationen so sein wird.
-
@Drgreentom sagte in C++ Lernen - Verständnisfragen:
18446744073709551615
Das ist das Maximale, was mit 64 Bit - als unsigned - darstellbar ist. Alle Bits sind auf 1 gesetzt.
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
Das dies als int interpretiert -1 ist, ist nirgends garantiert.
@DirkB sagte in C++ Lernen - Verständnisfragen:
Das ist das Maximale, was mit 64 Bit - als unsigned - darstellbar ist. Alle Bits sind auf 1 gesetzt.
Jetzt überlege ich gerade... Im Zweierkomplement wäre das vorzeichenbehaftet, ja immer -1. Darüber wird der Wert ja auch gesetzt. D.h. mit -1 vergleichen sollte auch immer gehen.
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
Jetzt überlege ich gerade... Im Zweierkomplement wäre das vorzeichenbehaftet, ja immer -1. Darüber wird der Wert ja auch gesetzt. D.h. mit -1 vergleichen sollte auch immer gehen.
Ich bin nicht sicher, ob du das richtige meinst, oder ob du dich ungünstig ausdrückst.
(unsigned)-1 == numeric_limits<unsigned>::max()
ist garantiert, ja. Aber nicht weil irgendwelche Annahmen zur internen Zahlenschreibweise garantiert wären, sondern weil unsigned-Typen garantiert der Überlaufarithmetik (bzw. hier halt Unterlauf) modulo ihres Maximalwertes gehorchen. Und du musst mit dem Vergleichswert ungeheuer aufpassen, wegen Integer Promotions:unsigned char c(-1); unsigned short s(-1); unsigned int i(-1); unsigned long l(-1); c == -1; // False s == -1; // False i == -1; // True l == -1; // True
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
Jetzt überlege ich gerade... Im Zweierkomplement wäre das vorzeichenbehaftet, ja immer -1. Darüber wird der Wert ja auch gesetzt. D.h. mit -1 vergleichen sollte auch immer gehen.
Das Zweierkomplement ist aber nirgends garantiert.
Auch wenn es schwierig ist, heutzutage was anderes zu finden.Ein int muss auch nicht 64 Bit groß sein, so dass der Wert nicht eindeutig ist.
size_t wurde nicht ohne Grund eingeführt.
-
@SeppJ Ja, zuviel überlegt.
@DirkB Nun, wenn ich mir einen 8 bit unsigned Typen nehme und einen 4 bit signed Typen. Und wenn man dem 4 Bit Typen den 8 Bit Typen zuweist in dem man die Bits, die nicht rein passen, einfach abschneidet, wäre das im Zweierkomplement wieder -1
8bit_usigned a = -1; //11111111 4bit_signed b = a; //1111 ->-1
Aber, dass wäre ja zu einfach. Gerade nochmal nachgelesen, wenn es nicht passt und der Zieltyp signed ist, war das Ergebnis bis c++20 tatsächlich Implementation defined.
Seit c++ 20 ist das fest definiert als der Wert modulo 2^(Anzahl Bits des Zieltypes)In meinem Beispiel also 255 mod(2^4) = 15
-
@Schlangenmensch sagte in C++ Lernen - Verständnisfragen:
Aber, dass wäre ja zu einfach. Gerade nochmal nachgelesen, wenn es nicht passt und der Zieltyp signed ist, war das Ergebnis bis c++20 tatsächlich Implementation defined.
Seit c++ 20 ist das fest definiert als der Wert modulo 2^(Anzahl Bits des Zieltypes)Das haben sie jetzt wirklich fest definiert? Das war doch immer ein Paradebeispiel für einen Fall wo undefiniertes Verhalten Optimierungen ermöglicht.
-
A prvalue of an integer type or of an unscoped (since C++11) enumeration type can be converted to any other integer type. If the conversion is listed under integral promotions, it is a promotion and not a conversion.
If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is implementation-defined (until C++20)the unique value of the destination type equal to the source value modulo 2n
where n is the number of bits used to represent the destination type. (since C++20). (Note that this is different from signed integer arithmetic overflow, which is undefined).https://en.cppreference.com/w/cpp/language/implicit_conversion
Wenn ich das richtig lese, sind Overflows aufgrund von Berechnungen explizit davon ausgenommen. Das heißt im Fall von
for
loops kann da immer noch optimiert werden.
-
Ah ja, das klingt nach einer guten Anpassung.
-
Auch hier wieder vielen Dank für eure Erläuterungen!
Kommen wir zu meinen nächsten Problem:
#include <iostream> #include <string> #include <vector> using namespace std; int main () { vector<string> ausgabe; string eingabe; int z=0; cout << "Wie viele Elemente soll der String haben? "; cin >> z; cout << endl; cout << "Sie wollen " << z << " Elemente eingeben." << endl; cout << endl; do { cout << "Etwas eingeben: "; getline (cin, eingabe); cout << endl; ausgabe.push_back(eingabe); cout << "Elemente im String: " << ausgabe.size() << endl; cout << endl; for (int k=0; k < ausgabe.size(); k++){ cout << ausgabe.at(k) << " "; } cout << endl; } while (z-1 >=ausgabe.size()); }
Kann mir jemand erklären warum die do-while Schleife die Eingabe-Taste von
cin >> z;
mit zählt und den ersten Loop quasi durchläuft?
-
@Drgreentom sagte in C++ Lernen - Verständnisfragen:
Kann mir jemand erklären warum die do-while Schleife die Eingabe-Taste von
cin >> z;
mit zählt und den ersten Loop quasi durchläuft?Weil das Zeichen der Eingabetaste ('\n') noch im Eingabestrom steht.
Beicin
werden nur Zeichen gelesen, die zu dem Typ passen.
Dann wird aufgehört und das nichtpassende Zeichen zurück gestellt.getline()
jedoch, liest das '\n' und hört dann auf.Mit
cin.clear(); cin.ignore(1000,'\n');
kannst du es überlesen