Methoden, die Zeiger zurückgeben



  • Nexus schrieb:

    Oder statt std::vector<char> kann man gleich std::string verwenden, das ist komfortabler im Umgang mit Zeichenketten.

    Du kannst std::string nicht mit einer C API verwenden.

    Oft hat man es mit C APIs zu tun die einen char* oder einen int* oder sonstwas erwarten. Hier hilft std::vector, da garantiert ist, dass du &vec[0] machen darfst um ein array zu bekommen. Dass ist bei std::string nicht der fall. Auch kann std::string nicht mit laengen aenderungen klar kommen. Weil er eben versteht was eine zeichenkette ist. std::vector ist da duemmer - ihm ist es egal. Ich sage ihm er hat 100 Elemente vom typ char und der rest ist ihm egal. Ich kann mit strcpy oder einer sonstigen C API (zB GetWindowText()) in ihm eine zeichenkette speichern. Natuerlich liefert mir dann vec.size() die anzahl an elementen (also 100) und nicht die laenge des strings, aber dafuer kann ich dann ja zB strlen(&vec[0]) verwenden...

    std::vector ist nicht perfekt um mit c apis zu kommunizieren, aber meistens gut genug. std::string dagegen ist nicht faehig mit einer c API zu kommunizieren, da &str[0] nicht garantiert einen gueltigen c string zu liefern und c_str() und data() liefern ja nur char const*



  • Im Falle von Arrays: std::vector
    Ansonsten: boost::shared_ptr (bzw. einer der anderen 3 Smartpointer. Im nächsten Standard gibt es es bessere Smartpointer in der Standardlib)



  • Hm... Okay, danke.

    Nun ja, für den Fall, wo man nicht auf C-APIs oder Arrays Rücksicht nehmen muss (der Threadersteller hat ja nichts diesbezüglich erwähnt, zumindest nicht explizit), würde ich trotzdem zu std::string tendieren. Bestimmte Methoden sind halt schon sehr praktisch.



  • TheBrain schrieb:

    Mir gehts eigentlich grundsätzlich mehr um das Problem der Zeigerrückgabe als um das Problem der Zeichenkettenverwaltung. Also wie man das am elegentesten löst, wenn man in einer Methode dynamisch Speicher reserviert, ihn aber in der gleichen Methode nicht wieder freigeben kann, weil Zeiger auf den reservierten Speicher Teil des Rückgabewertes sind.

    std::vector nehmen. Oder einen anderen container.
    lies nochmal meinen post, speziell:

    andere aufgaben und speicher management aufgaben zu übernehmen ist zuviel.

    Natuerlich kannst du einen per new allokierten speicher zurueck geben, aber das macht man nicht. es ist boese, es ist schlecht, es ist pfui. man verwendet in c++ abstraktion um das zu umgehen.

    denn das problem ist sobald man mit rohen speicher umherwirft, muss man sich nicht nur um die algorithmen zur bearbeitung des speichers kuemmern sondern eben auch um das management des speichers. Das sind 2 aufgaben fuer eine klasse/methode. Und wir wollen immer nur exakt eine aufgabe haben. denn desto mehr aufgaben wir erledigen muessen, desto mehr kommen sie einander in die quere.

    und wir haben auch sinnlose code verdoppelung. std::vector weiss bereits wie man ein dynamisches array anlegt, es vergroessert/verkleinert, bound checking macht, sich die groesse merkt und wann man es loeschen muss. wenn du den code jetzt immer verdoppelst wenn du ein array brauchst, dann machst du fehler - das ist einfach so. nicht nur dass du viel mehr schreibarbeit hast, du hast auch mehr fehler in deinem code.

    es spricht nichts dagegen wenn du eine eigene array klasse schreibst - aber du musst das rohe array abstrahieren.

    wenn du das alles trotzdem nicht willst, dann mach es genau so wie du es im ersten post gezeigt hast. aber dann hast du eben das problem dass du selber gut erkannt hast: wer ist fuer den speicher verantwortlich?

    weiters hast du ein problem wenn du den speicher spaeter nicht mehr mit new allokieren willst, sondern mit einem schnellen allokator oder sonstige tricks zur optimierung verwendest: der aufrufende code muss wissen wie du den speicher allokiert hast um ihn freizugeben. das ist furchtbar.

    in C umgeht man das problem ganz simpel: der callee allokiert nie speicher (es gibt ausnahmen, aber die sind idR schlechtes design). der caller muss immer den speicher bereitsstellen in den der callee reinschreibt. Das fuehrt natuerlich zu buffer overflows wenn man nicht aufpasst. In c++ hat man diese ganzen probleme nicht. std::vector und gut ist.



  • Nexus schrieb:

    Hm... Okay, danke.

    Nun ja, für den Fall, wo man nicht auf C-APIs oder Arrays Rücksicht nehmen muss (der Threadersteller hat ja nichts diesbezüglich erwähnt, zumindest nicht explizit), würde ich trotzdem zu std::string tendieren. Bestimmte Methoden sind halt schon sehr praktisch.

    Keine Frage. wenn du einen string haben willst, nimm std::string. std::vector ist nur als buffer gut - um eben mit C apis zu kommunizieren. wenn du aber das nicht brauchst, macht es keinen sinn strings in vectoren zu speichern...



  • Shade Of Mine schrieb:

    PS:
    wenn du das für eine kompatibilität mit einer C API brauchst:

    std::vector<char> vec(100);
    strcpy(&vec[0], "Hallo");
    

    Ja, ich brauche es tatsächlich wegen der Abwärtskompatibilität.
    Was würde denn bei folgendem Code passieren:

    char* data = new char[100];
    // data mit Inhalt füllen
    std::vector<char> vec(100);
    strcpy(&vec[0], data);
    delete[] data;
    

    Ich habe ja den Inhalt, auf den data zeigt, an die Adresse von &vec[0] kopiert. Das heißt, die Daten sollten dort ja noch sein. Aber wie muss ich mir vec nun vorstellen, stehen in vec[0] jetzt 100 Zeichen? Und in den restlichen vec[1] bis vec[99] nichts?

    //Edit: Und noch was: Was passiert bei strcpy(), wenn in data zufällig vor dem Ende irgendwo die Zeichenkette '\0' vorkommt? Bricht es dann ab? Na im Notfall kann ich ja noch ne gewöhnliche for-Schleife zum Kopieren nehmen ...



  • TheBrain schrieb:

    Ich habe ja den Inhalt, auf den data zeigt, an die Adresse von &vec[0] kopiert. Das heißt, die Daten sollten dort ja noch sein. Aber wie muss ich mir vec nun vorstellen, stehen in vec[0] jetzt 100 Zeichen? Und in den restlichen vec[1] bis vec[99] nichts?

    Wie gesagt, der std::vector verhält sich wie ein Array. vec[0] repäsentiert dabei das erste Zeichen, die höheren Indizes sind mit den restlichen Zeichen gefüllt.

    TheBrain schrieb:

    //Edit: Und noch was: Was passiert bei strcpy(), wenn in data zufällig vor dem Ende irgendwo die Zeichenkette '\0' vorkommt? Bricht es dann ab? Na im Notfall kann ich ja noch ne gewöhnliche for-Schleife zum Kopieren nehmen ...

    strcpy() liest einen C-String, also bis und mit der Nullterminierung. Zeichen danach werden ignoriert. Das heisst, beim Schreiben steht in den Elementen nach '\0' Schrott.



  • Wenn du chars mit '\0' drinnen kopieren musst, dann musst du die Länge selbst wissen. In dem Fall kannst du einfach memcpy statt strcpy verwenden.

    BTW: zum Thema "Methoden, die Zeiger zurückgeben" gibt es ein recht gutes Paper von Scott Meyers namens "The Resource Return Problem". Darin geht's allerdings um C++ Konstrukte, auf den Teil "C API Kompatibilität" geht er dabei IIRC nicht ein.
    http://www.aristeia.com/Papers/resourceReturnProblem.txt



  • Und was spricht gegen eine gewöhnliche for-Schleife, wenn ich die Größe eh kenne:

    for (int i = 0; i < length; i++)
     vec.push_back(data[i]);
    

    Oder sind strcpy() und memcpy() da effizienter?



  • TheBrain schrieb:

    Und was spricht gegen eine gewöhnliche for-Schleife, wenn ich die Größe eh kenne:

    for (int i = 0; i < length; i++)
     vec.push_back(data[i]);
    

    Oder sind strcpy() und memcpy() da effizienter?

    std::copy(..)



  • copy und push_back sind Äpfel und Birnen

    es sei denn man macht copy mit back_inserter - aber das wäre wohl jetzt zu kompliziert...



  • TheBrain schrieb:

    Und was spricht gegen eine gewöhnliche for-Schleife, wenn ich die Größe eh kenne:

    for (int i = 0; i < length; i++)
     vec.push_back(data[i]);
    

    Oder sind strcpy() und memcpy() da effizienter?

    strcpy und memcpy sind vermutlich effizienter als push_back, was daran liegt dass push_back die size jedesmal anpassen muss. keine ahnung ob compiler schlau genug sind das wegoptimieren zu können - vermutlich eher nicht.

    wenn du std:: dinge mit strcpy/memcpy vergleichen willst, dann mach zuerst ein resize() auf den vevtor und verwende dann std::copy mit normalen iteratoren (kein back_inserter!). das sollte dann auf gut optimierenden compilern gleich schnell wie memcpy sein (vorausgesetzt der typ des vectors ist ein POD), da der compiler die einfache kopierschleife erkennt und dann sowieso durch memcpy ersetzt.


Anmelden zum Antworten