Frage zur Funktionsweise einer Funktion



  • Hallo zusammen,
    ich habe diese Funktion, die Wörter eines Strings durch andere ersetzt:

    int replaceAll(string& rstr,const string& oldStr,const string& newStr)
    {
    	int lenOld = oldStr.length(),
    	    lenNew = newStr.length(),
    		pos    = 0,
    		count  = 0;
    
    	while((pos = rstr.find(oldStr,pos)) != string::npos)
    	{
    		rstr.replace(pos,lenOld,newStr);
    		pos += lenNew;
    		++count;
    	}
    
    	return count;
    }
    

    Ein Beispielaufruf könnte so aussehen:

    string text = "Der Wetter ist toll.";
    count = replaceAll(text,"toll","schön");
    

    Nun habe ich folgende Fragen:

    1.) Warum funktioniert die Funktion nicht, wenn ich den zweiten und dritten Parameter nicht als const deklarier?

    2.) Wenn ich jetzt einen Aufruf mache, dann wird in der while - Schleife bei der Stelle pos, also 0, nach dem String oldStr. Da an dieser Stelle aber dieser String nicht zu finden ist, dann müssten doch npos zurückgegeben werden und die Schleife müsste sofort beendet sein. Wo liegt mein Denkfehler?

    Vielen Dank
    lg, freakC++



  • 1. Da du ja String-Literale übergibst, können diese zwar temporär in "const string&" gewandelt werden, nicht aber in (nicht-konstante) Referenzen, denn nach Aufruf der Funktion hätte man keinen Zugriff mehr auf dieses temporäre Objekt (und daher wird es vom Compiler als Fehler angesehen).

    2. verwende statt 'int' besser 'size_t' (ansonsten sehe ich ersteinmal keinen anderen Fehler).



  • freakC++ schrieb:

    1.) Warum funktioniert die Funktion nicht, wenn ich den zweiten und dritten Parameter nicht als const deklarier?

    Die Stringliterale (vom Typ const char[N+1] mit N=Länge) werden zu std::string-Objekten konvertiert. Diese Objekte sind allerdings "namenlos", "temporär". Wenn Du beispielsweise eine Funktion mit der Signatur

    void foo(string & referenz);
    

    hast, sieht es so aus, als ob sie den per Referenz übergebenen String modifiziert/modifizieren soll. Da Du eine Modifikation eines namenlosen String-Objektes gar nicht bemerken würdest, lässt Dich der Compiler kein namenloses Objekt an eine nicht-konstante Referenz binden. Das ist eine reine Sicherheitsmaßnahme, die man eingebaut hat, um Programmierfehler zu reduzieren.

    In Deinem Fall hast Du nicht vor, diese Objekte zu verändern, solltest das also auch kennzeichnen:

    void foo(string const & referenz);  // so, oder
    void foo(const string & referenz);  // so (ist das gleiche)
    

    Nun ist klar, dass foo das per Referenz übergebene Objekt nicht verändern will/soll. Es ist daher unbedenklich, die Referenz mit einem temporären Objekt zu initialisieren.

    In jedem guten C++ Buch sollte das erklärt werden. Das Paradebeispiel ist folgendes:

    void inc(long& x) {
      ++x;
    }
    
    int main() {
      int t = 2;
      inc(t);
      cout << t << endl;
    }
    

    Es kompiliert glücklicherweise nicht. Gäbe es den oben erwähnten Schutz nicht, würde das Programm eine 2 statt einer 3 ausgeben, da 'x' ein durch die Konvertierung von int->long erzeugtes temporärs Objekt referenziert.

    Übrigens hat das nichts mit Funktionen selbst zu tun:

    int         i    = 23;
     int       & ri   = i;   // ok
     int const & cri1 = i;   // ok
     int const & cri2 = i+5; // ok
     int       & ri2  = i+5; // Fehler! (compile-time)  
     assert( &i == &ri );   // ri referenziert i
     assert( &i == &cri1 ); // cri1 auch
     assert( &i != &cri2 ); // cri2 nicht!
    

    Welches C++ Buch benutzt Du, was Referenzen und const nicht gut erklärt?

    Gruß,
    SP



  • Hallo,
    vielen Dank für die Erklärung. Ich benutze eigentlich ein sehr gutes Buch, nämlich "C++ Lernen und professionell anwenden" von Ulla Kirch-Prinz und Peter Prinz. Das Problem ist zwar, dass alles sehr seriös erklärt wird, doch wenn man sich das selber beibringt und wirklich alles verstehen möchte, dann fallen auch solche Fragen an. Ich könnte auch einfach drüberwegsehen, doch möchte ich verstehen, was der Compiler macht oder auch nicht macht!

    Vielen Dank
    lg, freakC++


Anmelden zum Antworten