Parameterübergabe als Referent oder Zeiger oder Kopie



  • Hallo,

    Welche Art der Parameterübergabe ist am Ressourcensparendsten?

    void Funk(std::string str);
    
    void Funk(const std::string& str);
    
    void Funk(std::string* str);
    

    Oder ist das am Ende egal, weil alle drei Wege gleich viel Speicher/Ressourcen verschwenden? Ich würde mich über hilfreiche Antworten freuen 🙂


  • Mod

    Unhilfreiche, aber richtige, Antwort: Kommt drauf an...

    🙂

    Tut mir leid, so ist es nun mal einfach.

    Der Pointer und die Referenz sind von den Ressourcen aber gleich. Eventuell, in konstruierten Fällen, könnte sogar die Referenz besser sein. Aber niemals wird der Pointer ressourcensparender sein als die Referenz.

    Ansonsten kommt's auf die Kopierkosten der Daten an. Einen ganz allgemeinen String in dem alles drin stehen kann, würde ich immer per Referenz übergeben. Und wieder kann man Fälle konstruieren, wo das eventuell Optimierungen verhindert oder an anderer Stelle zu viel Overhead verursacht. Aber als Dauemregel würde ich alles mit unbekannter Größe (Zeicheketten, Container) per Referenz übergeben. Und bei bekannter Größe würde ich ab 2-4 Maschinenworten über Referenzen nachdenken. Und wenn es so kritisch ist, dann lieber nochmal messen, man wundert sich oft, wie schlecht oder gut manche Dinge in der Praxis sind.



  • SeppJ schrieb:

    Daumenregel

    Die ergibt sich dann wohl, wenn man eine Faustregel durch PI teilt.



  • volkard schrieb:

    SeppJ schrieb:

    Daumenregel

    Die ergibt sich dann wohl, wenn man eine Faustregel durch PI teilt.

    😃



  • Das kommt darauf an, was du mit dem string in deiner Funktion machen willst:

    a) Du willst ihn nur auslesen: Variante 2 (const std::string &) -> es wird keine Kopie erstellt
    b) Du musst ihn in deiner Funktion verändern (z.B. was dran hängen oder sowas): Variante 1 (std::string) -> string wird in Funktion kopiert



  • Mit C++0x wird die Übergabe per Value wieder sehr attraktiv.



  • Ich glaube der thread Ersteller sollte sich vorerst noch nicht mit RValues und allem was damit zusammen hängt herumschlagen 🙂



  • Nimm die

    void foo(string const& cref);
    

    Variante, sofern Du intern das Ding nicht kopieren musst. Wenn Du Dich genötigt siehst, das String-Objekt intern zu kopieren, dann lohnt sich schon die Übergabe "by Value".

    void foo(string const& cref)
    {
      string kopie = cref; // <-- Manuelle Kopie des string-Objekts (doof)
      std::reverse(kopie.begin(),kopie.end());
      std::cout << kopie << std::endl;
    }
    

    Wenn man das Kopieren des Parameters dem Compiler überlässt, kann er diese Kopie ggf wegoptimieren und man spart damit Zeit. Besser ist also:

    void foo(string value)
    {
      std::reverse(value.begin(),value.end());
      std::cout << value << std::endl;
    }
    

    Wegen der möglichen "unnötige Kopie kann ggf wegoptimiert werden"-Sache, kann man zB auch das hier schreiben:

    class person {
      string name;
      ...
    public:
      explicit person(string na)
      { this->name.swap(na); }
    };
    
    string namens_eingabe();
    
    int main()
    {
      person x ( namens_eingabe() );
    }
    

    Selbst wenn der Conpiler das String-Argument kopiert, ist diese Kopie wenigstens nicht umsonst gewesen, da die Kopie für das person-Objekt verwendet werden kann. Im besten Fall wird hier nämlich GAR nichts unnötig kopiert. Ein Compiler kann die Funktion namens_eingabe den Ergebnis-String direkt dort konstruieren lassen, wo es dann den Namen 'na' bekommt (siehe person-Konstruktor). Der Konstruktor erzeugt zunächst ein zweites, leeres String-Objekt. Dann wird per swap veranlasst, dass der Inhalt ausgetauscht werden soll. Bein std::string ist swap eine Operation, die fast nichts kostet (konstante Laufzeit).

    Das war sicherlich zuviel des Guten ... aber so ist das eben ... 😃

    kk


Anmelden zum Antworten