Doppelpunkt Bedeutung in Bedingung



  • Ja, er will das Verhalten im Grenzbereich testen, was mal eine seiner guten Ideen ist.


  • Gesperrt

    #include <limits.h>
    #include <string>
    #include <iostream>
    
    unsigned long long getNumber(std::string s)
    {
        unsigned long long r = 0;
        for (char c : s) {
            int i = c - '0';
            if (i < 0 || i > 9) {
                continue;
            }
            if (r > ULLONG_MAX + (r * 10 + i)) {
                return ULLONG_MAX;
            }
            r = r * 10 + i;
        }
        return r;
    }
    
    int main(int argc, char* argv[])
    {
        using namespace std;
        string s = "98765432111111111101";
        cout << getNumber(s) << endl;
        for (unsigned long long test = ULLONG_MAX - 10; test != ULLONG_MAX; test++) {
            cout << getNumber(to_string(test)) << endl;
        }
        for (unsigned long long test = ULLONG_MAX; test != ULLONG_MAX - 10; test--) {
            cout << getNumber(to_string(test)) << endl;
        }
        cout << getNumber("-123trash") << endl;
        return 0;
    }
    

    ginge auch noch, aber das führt vielleicht zu Ergebnissen/Ausgaben, die nicht mehr nachvollziehbar wären. Insbesondere könnte "-123trash" -> 123 ein unerwünschtes oder unerwartetes Verhalten sein.

    Aber das kommt auf den Kontrakt an.



  • Hi Zusammen, jetzt habe ich noch eine Ergänzung zu der Frage. Im Buch in Kapitel 2. Funktions-Templates ist in dem Beispiel eine for-Schleife wie folgt angegeben:

    	for (const auto& element : vek) {
    		if (kleiner(max, element)) {
    			max = element;
    		}
    

    Was genau bewirkt das Referenz-Zeichen in dem Fall bei der Deklaration von element? Wenn ich es weglasse ändert sich erstmal gar nichts. So wie ich das verstehe, kann ich doch element durch const sowieso nicht ändern.


  • Mod

    Es ist schon richtig, dass das eine Referenz anlegt, und dass das Objekt dahinter trotz Referenz nicht änderbar ist. Aber Referenzen haben auch einen Sinn und Zweck jenseits von "darüber kann man das Objekt indirekt ändern": Man spart dadurch eine Kopie. Das kann in zwei Fällen nützlich sein. Zum einen gibt es Objekte, die man gar nicht kopieren kann (Streams beispielsweise). Zum anderen kann das auch effizienter sein, und zwar dann wenn das Erstellen einer Kopie sehr teuer ist. Stell dir beispielsweise vor, in deinem Vektor lägen lauter große Bilder.

    Referenzen auf const-Objekte sind sehr üblich und du wirst ihnen noch oft begegnen.



  • @SeppJ Hi SeppJ, das verstehe ich noch nicht so ganz, weil ich nach der Begründung im Buch davon ausgegangen bin, dass sowieso eine Kopie aller Werte des jeweiligen Elements des Containers angelegt wird (siehe Zitat unten).

    Aber verstehe ich dich richtig, dass der folgende Code - ohne Referenz - ein Objekt element anlegt, welches alle Elemente von vek kopiert hat:

    for (const auto element : vek)
    

    Und im folgenden Fall wird keine Kopie angelegt.

    for (const auto& element : vek)
    

    Ich glaube was mir fehlt ist die volle Bedeutung des Doppelpunktes. Nach meiner Logik fehlt noch die Initalisierung von element in folgendem Sinne:

    for (const auto& element{vek} : vek)
    

    So hatte ich zumindest Referenzen aus dem Buch verstanden. element ist eine Referenz auf ein Objekt. Aber ich muss das zu referenzierende Objekt ja auch erstmal angeben. Oder ist dies wieder durch "range based for" automatisch gegeben?

    @Belli sagte in Doppelpunkt Bedeutung in Bedingung:

    In der pdf-Version des Buches steht dazu auf Seite 98:

    Zitat:
    Auf die Zählvariable kann verzichtet werden, wenn auf alle Elemente des Containers
    zugegriffen werden soll, weil dann die folgende Kurzform (englisch range based for)
    verwendet werden kann:

    for (double wert : einVektor) { // Kopie jedes Elements
    cout << wert << ’\n’;
    }
    

    Man kann die Schleife so lesen: Führe den Schleifenkörper für alle Objekte wert in
    einVektor aus. Die lokale Variable wert ist dabei eine Kopie des jeweiligen Elements
    des Containers.
    Die Kopie kann innerhalb der Schleife verändert werden, ohne dass sich
    die Änderung auf den Container auswirkt, etwa:

    for (double wert : einVektor) { // veränderliche Kopie
    wert = 2.0 * wert;
    cout << wert << ’\n’;
    }
    

    Ende des Zitats



  • @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    Aber verstehe ich dich richtig, dass der folgende Code - ohne Referenz - ein Objekt element anlegt, welches alle Elemente von vek kopiert hat:

    Nein. Insbesonders der hintere Teil passt nicht: ... welches alle Elemente von vek kopiert hat

    In "element" ist jeweils nur ein Element (steht doch auch so im fett hervorgehobenen Zitat). Im ersten Schleifendurchlauf wird in element das erste Element aus dem Vektor kopiert. Dann kommt der Schleifenkörper. Danach wird in element das zweite Element aus dem Vektor kopiert und so weiter.

    Mit & ist element im 1. Durchlauf eine Referenz auf das erste Element, im 2. Durchlauf eine Referenz auf das 2. und so weiter.



  • @Kvothe Ich glaube, dass verstehst du noch nicht richtig.

    for (const auto element : vek)
    

    In jedem Schleifendurchlauf wird eine Kopie eines Element des Vektors angelegt. D.h. insgesamt wird jedes Element einmal kopiert.

    for (const auto& element : vek)
    

    In jedem Schleifendurchlauf wird eine Referenz auf ein Element des Vektors angelegt. D.h. die Daten, die an der jeweiligen Stelle des Vektores liegen, werden nicht kopiert.

    for (const auto& element{vek} : vek)
    

    Das ist Blödsinn. Der : Operator sorgt dafür, das element richitg initialisiert ist. Außerdem willst du immer nur auf ein Element aus dem Vektor zugreifen, d.h. es würde eh keinen Sinn ergeben, dass mit dem gesamten Vektor zu initialisieren.



  • @wob Ah okay :), vielen Dank!
    Ich bin bisher davon ausgegangen, dass "element" eine identische Kopie des gesamten Vektors ist und dann dessen Elemente durchgezählt werden. Damit ist einiges klarer.



  • @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    Ich glaube was mir fehlt ist die volle Bedeutung des Doppelpunktes.

    Das kann man sich mit C++ Insights ansehen. Für einen Anfänger ist das vielleicht etwas unleserlich, etwa schöner sieht es so aus:

        const std::vector<char> arr{ '1', '2', '3' };
    
        for(const char& c : arr)
        {
           std::cout << c;
        }
    

    =>

       const std::vector<char> arr{ '1', '2', '3' };
      {
        const std::vector<char> & __range1 = arr;
        auto __begin1 = __range1.begin();
        auto __end1 = __range1.end();
        for(; __begin1 != __end1; __begin1++) {
          const char & c = *__begin1;
          std::cout <<  c;
        }
        
      }
    


  • @manni66 Hi Manni, das ist super und erklärt es bestens. Danke dir!


Anmelden zum Antworten