Hängende Zeiger vermeiden



  • @chris4cpp
    Ja, das ist bei templates leider so. Und wenn man sich damit noch nicht beschäftigt hat steht man wie der Ochs vorm Berg und kann mit der Fehlermeldung so gar nichts anfangen. Das kommt aber mit der Zeit.



  • @chris4cpp sagte in Hängende Zeiger vermeiden:

    Kann es sein dass die Fehlermeldungen zu schwierig zu lesen sind, weil die SmartPointer mit Templates realisiert sind? An Templates wage ich mich noch überhaupt nicht ran, das sieht alles tierisch kompliziert aus. Es wird zwar immer geschrieben wie elegant man damit Sachen lösen kann, aber mich grault es jetzt schon vor kryptischen Fehlermeldungen.

    Das ist ein Dauerbrenner in C++. Vor etlichen Jahren wollte man Concepts einführen, damit die Fehlermeldungen endlich sinnvoller lesbar sind. Concepts sind noch immer kein Teil der Sprache. Man sollte mit Templates selbst schreiben erst dann anfangen, wenn man die Sprache selbst halbwegs beherrscht.


  • Mod

    Du solltest übrigens nicht annehmen, dass du explizite Smartpointer brauchst, nur weil eine API Zeiger verlangt. Viele APIs brauchen Zeiger, aber nur wenige benutzen diese auch zur Ressourcenverwaltung. Oft geht es nur um die Übergabe von Daten im C-Stil.

    Ein bekanntes Beispiel ist die Stringverarbeitungs-API von C selbst. Die kannst du problemlos mit std::vector oder std::string benutzen, ohne irgendwo einen Smartpointer im Programm zu haben. Da lässt du den String/Vector alles intern regeln, und wenn du (aus unerfindlichen Gründen) unbedingt die Schnittstelle für C-Strings nutzen möchtest, dann würdest du einen Zeiger auf deren interne Datenfelder übergeben. Nicht ohne Zufall stellen diese Container eine passende Schnittstelle zur Verfügung:

        #include <vector>
        #include <string>
        #include <cstring>
        using namespace std;
         
        int main() {
        	string foo = "foo\0";
        	vector<char> bar(4);
        	strcpy(bar.data(), foo.data());
        	printf("%s", bar.data());
        }
    

    Das geht natürlich dann nicht mehr, wenn diese APIs selber Ressourcen verwalten und beispielsweise einen Handler rausgeben. Dann muss doch ein Smartpointer her (oder eine Wrapperklasse). Zum Beispiel die Dateizugriffsschnittstelle von C:

          void close_file(std::FILE* fp) { std::fclose(fp); }
    
          // ...
    
          std::unique_ptr<std::FILE, decltype(&close_file)> fp(std::fopen("demo.txt", "r"),
                                                               &close_file);
    

    (Beispiel von https://en.cppreference.com/w/cpp/memory/unique_ptr)



  • Kleine Optimierung:

    struct file_closer {
        void operator()(std::FILE* fp) const {
            std::fclose(fp);
        }
    };
    
    void test() {
        std::unique_ptr<std::FILE, file_closer> fp(std::fopen("demo.txt", "r"));
    }
    


  • @SeppJ sagte in Hängende Zeiger vermeiden:

    	string foo = "foo\0";
    

    Die '\0' ist doppelt gemoppelt und ein vector<char> bar(4) reicht dafür auch nicht.

    edit: Ja, ok, std::strcpy() hört natürlich bei der ersten '\0' auf.

    @chris4cpp Rohe Zeiger per se sind nicht böse. Rohe besitzende Zeiger sind böse.


  • Mod

    @Swordfish sagte in Hängende Zeiger vermeiden:

    Die '\0' ist doppelt gemoppelt und ein vector<char> bar(4) reicht dafür auch nicht.

    edit: Ja, ok, std::strcpy() hört natürlich bei der ersten '\0' auf.

    Auch die erste Aussage ist nicht richtig:
    https://ideone.com/wubSCh

    Tzz, tzz, tzz. Immer diese Kinners, die denken, sie könnten mir was von C-Strings erzählen…
    😛



  • @Swordfish sagte in Hängende Zeiger vermeiden:

    Die '\0' ist doppelt gemoppelt

    Steht und mir ist auch nicht klar warum Du die 0 explizit hinschreiben möchtest.



  • @SeppJ: Hattest du den falschen Code gepostet (mit "foo\n" anstatt "foo\0")?

    -> korrigierter Code

    Ein String kann zwar '\0' speichern, aber der Konstruktor string(const char *) liest nur bis zu diesem Zeichen (exklusiv). @Swordfish hat also Recht mit seiner Aussage. 😉



  • Danke euch für die Zusatzinfos, das mit dem Deleter bei SmartPointern kannte ich auch noch nicht, das ist ja genial.

    Hier hatte ich auch schon mal die data() Methode vom std::vector im Einsatz. Das ist auch eine Stelle wo ich vorher nur rohe Zeiger auf ein Char CArray eingesetzt hatte:

    Framebuffer::Framebuffer(int width, int height)
    	:
    	width_(width),
    	height_(height),
    	length_(width * height << 2),
    	yoffset_(width << 2),
    	buffer_(width * height << 2),
    	color_(Color(0, 0, 0))
    {
    	img_ = QImage(buffer_.data(), width_, height_, Framebuffer::format_);
    }
    
    

    Toll was man alles bei so eine etwas größeren Testprojekt dazulernt. Ich hatte ja schon diverse Male mit C++ und auch C angefangen(früher mal Assembler auf dem Amiga), aber dort nur stupide alle Möglichen Sachen in der Konsole ausprobiert und dann genauso schnell wieder alles vergessen was ich gelernt habe. Hier bei dem Projekt ärgert es mich richtig wenn ich nicht weiter komme und grobe Schnitzer drin sind, dann will ich es besser machen.



  • @chris4cpp sagte in Hängende Zeiger vermeiden:

    Wenn ich noch wirklich einen Zeiger brauchte kam meist shared_ptr (...) zum Einsatz.

    Spannend. Im Regelfall benutzt man für besitzende Zeiger std::unique_ptr. Shared_ptr braucht man (=ich, Schluss von mir auf andere...) eher sehr selten, nämlich wenn die Ressourcen wirklich keinen eindeutigen Besitzer haben. Also: bist du sicher, dass du wirklich überall, wo du shared_ptr benutzt, wirkich shared_ptr statt unique_ptr (bzw. rohe, nicht besitzende Zeiger) brauchst?



  • @wob Man kann mit shared_ptr viel einfacher die Scheuklappen aufsetzen und Komponenten nur für sich genommen betrachten und entwickeln. "Geborgte" Pointer sind ... oft keine so gute Idee wie sie anfangs zu sein scheinen.

    Und mit "geborgte" Pointer meine ich: rohe, nicht besitzende Zeiger die länger leben als der Funktionsaufruf bei dem sie übergeben werden. Also die Sorte wo ich einem Objekt einen Zeiger gebe, das merkt sich den Zeiger dann, und ich bin dann verantwortlich dafür das Objekt lange genug am Leben zu halten.



  • @wob Nein, ich bin mir nicht sicher ob nicht auch ein unique ausgereicht hätte. Der Shared Pointer klang von der Beschreibung her sehr einfach, weil ich hier wirklich die Verantwortung sehr simple abgeben kann.


Anmelden zum Antworten