Wann benutzt ihr direkt Pointer?



  • und wo ist der unterschied ob ich nun einfach direkt die instanz rumgebe oder einen pointer der instanz?



  • asd_maus schrieb:

    und wo ist der unterschied ob ich nun einfach direkt die instanz rumgebe oder einen pointer der instanz?

    Das eine ist eine Kopie und das andere nicht.



  • asd_maus schrieb:

    und wo ist der unterschied ob ich nun einfach direkt die instanz rumgebe oder einen pointer der instanz?

    Meinst du mit INstanz direkt rumgeben Kopien der Instanz??



  • Generell:

    Immer dann wenn es den "NULL Fall gibt" also ich auch ungueltigkeits-Werte zurueckgeben muss, und die Klasse auf die ich zeig zu komplex ist, um eine Expliziete Ungueltigkeit-Instanz zu erzeugen.
    UND wenn Templates (Smartpointer) als Parameter nicht gehen.

    Praktisch:
    Interfaces die ueber Dll grenzen gehen muessen/Könnten und Faktory-like Instanzen nach dem Create / Destroy Muster erzeugen ...

    Ansonsten nehm ich Referenzen, und wenn die ned gehen dann smartpointer ...

    Und natuerlich wenn ich "Datenstrukturen" im Speicher liegen habe und local innerhalb eines Algos mir Stellen darauf merken muss ... dann nehm ich fuer die variablen auch zeiger, klar ...

    Ciao ...



  • Wenn ich nicht groß damit arbeiten muss, dann nehm ich immer const char* statt std::string. Wer std::string nutzt braucht nur ein c_str und allen anderen zwinge ich nicht std::string und sinnlose Kopiererei und Allocation auf.



  • Nicht besitzende Memberpointer

    class Ding
    {
    public:
      Ding(const Ding& deinNachbar) :nachbar(&deinNachbar){}
    protected:
      const Ding& MeinNachbar() const {return *nachbar;}
    private:
      const Ding* nachbar;
    };
    

  • Mod

    Aktuell: Ganz klassisch als Verweise auf Objekte, die in einer Liste gespeichert sind. So markiere ich ein paar spezielle Objekte aus dieser Liste, die Verweise sind dann in einer anderen Liste gespeichert. Warum keine Iteratoren? Weil man aus einem Iterator leicht einen Pointer bekommen kann, aber wenn man nur einen Pointer hat, dann kommt man nur über Compilererweiterungen an einen passenden Iterator. Und mit letzterem bin ich ordentlich auf die Schnauze gefallen, als das nicht mehr ging.



  • Verweise, die nicht besitzend sind und für die Referenzen zu wenig flexibel sind.

    Tachyon schrieb:

    Ich habe, mal abgesehen vom char**-Paramater der main, keine rohen Pointer in meinem aktuellen Projekt.

    Was verwendest du, wenn Referenzen nicht ausreichen, z.B. weil du Verweise nachträglich ändern musst oder NULL haben willst? shared_ptr ?



  • Nexus schrieb:

    Verweise, die nicht besitzend sind und für die Referenzen zu wenig flexibel sind.

    Tachyon schrieb:

    Ich habe, mal abgesehen vom char**-Paramater der main, keine rohen Pointer in meinem aktuellen Projekt.

    Was verwendest du, wenn Referenzen nicht ausreichen, z.B. weil du Verweise nachträglich ändern musst oder NULL haben willst? shared_ptr ?

    unique_ptr oder shared_ptr. Je nach Anwendungsfall. Manchmal auch Iteratoren aus einer Liste.

    Edit: Ach ja, bei boost/std::bind benutze ich auch noch rohe Zeiger.



  • justchris schrieb:

    Wann benutzt ihr direkt Pointer?

    Eigentlich nur wenns ne Schnittstelle erfordert oder wenns sich durch Profilen tatsächlich als nötig erweisen sollte, was aber eigentlich nur vorkommt wenn ich über die Pixel eines Bilds renne. Sonst immer per default unique oder shared pointer.



  • Dobi schrieb:

    justchris schrieb:

    Wann benutzt ihr direkt Pointer?

    Eigentlich nur wenns ne Schnittstelle erfordert oder wenns sich durch Profilen tatsächlich als nötig erweisen sollte, was aber eigentlich nur vorkommt wenn ich über die Pixel eines Bilds renne. Sonst immer per default unique oder shared pointer.

    Warum? Warum nutzt man das bei Parametern?

    void foo(std::shared_ptr<LargeObject> pointer)
    {
      if (pointer)
      {
      }
    }
    // Statt
    void foo(LargeObject* pointer)
    {
      if (pointer)
      {
      }
    }
    

    Wo ist der Vorteil? Man bindet den Aufrufer an einen Zeigertyp, und man bindet die Funktion an Teile der Standardbibliothek, bei unique_ptr bindet man sogar an C++11. Und wozu das Ganze? Es hat doch überhaupt keine Vorteile.



  • Irgendwann könnte das ganze ja multithreadig werden. 😉
    Aber da bei sowas würd ich eigentlich eh erstmal eine Referenz nehmen. Ich kann mich grad gar nicht dran erinnern, dass ich in meinen letzten Projekten mal prüfen musste, ob ein Zeiger null ist. Falls das ein Indikator für Design-Probleme ist, flame ruhig. Ich weiß, dass es noch viel für mich zu lernen gibt.



  • Wenn der Zeiger nicht nullptr sein darf, nimmst du natürlich eine Referenz. Wenn nicht, nimmst du halt einen Zeiger. Aber ein shared_ptr oder ein unique_ptr& macht eigentlich aus oben genannten Gründen nie Sinn. unique_ptr ist toll, wenn man auch gleich Besitz übergeben möchte. shared_ptr ist toll, wenn man wirklich shared ownership möchte. (Auch wenn ich das noch nie gebraucht habe.) Aber ansonsten sind "rohe" Pointer und Referenzen doch einfach zu bevorzugen?



  • Achso, klar. Grundsätzlich nehm ich natürlich Referenzen. Wenn die aber nicht gehen, dann shared oder unique pointer. Ich wüsste gerade keine Situation in der Referenzen nicht passen würden und gleichzeitig shared/unique nicht hilfreich wäre. Fällt dir eine ein?



  • Dobi schrieb:

    Ich wüsste gerade keine Situation in der Referenzen nicht passen würden und gleichzeitig shared/unique nicht hilfreich wäre. Fällt dir eine ein?

    Sogar zwei, wie schon erwähnt: Nicht-besitzende Verweise, die sich ändern oder die ungültig sein können.



  • cooky451 schrieb:

    ein [...] unique_ptr& macht eigentlich aus oben genannten Gründen nie Sinn.

    Einen unique_ptr& hatte ich schon öfters. Das ist sinnvoll, wenn die Funktion den Zeiger umbiegen darf, aber keinen Besitz daran hat.

    Bei meinem aktuellen Projekt habe ich mir testweise eine Klasse raw_ptr geschrieben. Mittlerweile frage ich mich, warum es den noch nirgens gibt, obwohl er doch viele Vorzüge hat:

    • Zeigerarithmetik und 0 kann verboten, aber Zuweisungen erlaubt werden
    • Er verhält sich zu dem normalen Pointer wie die C++-Casts zu den C-Casts: Er hat einen Namen wie ein Schlüsselwort. Dadurch wird der Code sprechender und man kann das Sourcefile nach Vorkommen untersuchen (das ist nicht zu unterschätzen 😉 )
    • Die Syntax gleicht der Smartpointern, man weiss sofort, wo das const hingehört)
    • Die Klasse eignet sich für assert, logging und solche Sachen
    • Man muss nicht mehr von void* casten

    Das wichtigste ist, dass man die Ambivalenz des Zeigers von einem Iterator und einer veränderbaren Referenz strikt aufteilen kann: Einmal in Iteratoren und einmal in den raw_ptr. Für die Fälle, wo man wirkliche Pointer braucht (z.B. für Bildbearbeitung), dann kann man diese immer noch nehmen. Aber für die meisten Fälle verwende ich das Paar unique_ptr / raw_ptr . Irgendwie ergänzen sich die ideal.



  • Ja, das hab ich schon verstanden.
    Ich bin bisher nur noch nicht in eine Situation gekommen, in der ich es mit nicht-besitzenden Verweisen, die sich ändern oder ungültig sein können, zu tun hatte. Wenn mich C++11-STL-Abhängigkeit nicht stört, und es nichts mit Performance zu tun hat, warum sollte ich dann nackte Zeiger incl. der dazugehörigen Gefahren benutzen? Wenn ein Verweis ungültig werden kann, hat man es mit schlauen Zeigern doch meist leichter. Den pädagogischen Faktor, dass man eventuell nicht mehr drüber nachdenkt, wo man seine Objekte überhaupt zerstört, lass ich mal außer acht. Darüber hab ich mir früher lang genug Gedanken gemacht. 😉
    Vielleicht ist es letztendlich auch einfach eine Frage des persönlichen Geschmacks.



  • grux schrieb:

    Bei meinem aktuellen Projekt habe ich mir testweise eine Klasse raw_ptr geschrieben. Mittlerweile frage ich mich, warum es den noch nirgens gibt, obwohl er doch viele Vorzüge hat

    Wahrscheinlich weil wichtigere Probleme vorhanden sind 😉

    Ich hatte tatsächlich schon die selbe Idee, aber vermisst habe ich die Funktionalität noch nicht wirklich. Am ehesten relevant für mich wäre die Möglichkeit, Initialisierung zu erzwingen. Aber ein simples * ist eben doch schöner :p

    Viel schlimmer finde ich die Tatsache, dass niemand einen kopierbaren Smart-Pointer braucht. Irgendwie scheint es vielen Leuten zu gefallen, jeweils von Neuem die Big Three zu implementieren und sich mit fehleranfälligem Boilerplate-Code rumzuschlagen.

    Dobi schrieb:

    Wenn mich C++11-STL-Abhängigkeit nicht stört, und es nichts mit Performance zu tun hat, warum sollte ich dann nackte Zeiger incl. der dazugehörigen Gefahren benutzen?

    Weil dir weder unique_ptr noch shared_ptr was bringt, wenn du keinen Besitz zu verwalten hast. Wenn die Situation bei dir nicht vorkommt, ok 🙂



  • Dobi schrieb:

    dazugehörigen Gefahren

    Die da wären? Ausversehen ++ schreiben? Na ja, das ist doch eher unwahrscheinlich. Und ptr*& habe ich auch super selten genutzt, das wäre in der Tat ein Vorteil, quasi eine Referenz auf einen Pointer der nicht 0 sein kann. Dann braucht man aber noch eine Klasse, die wieder 0 sein kann. Nee. So schlimm ist das auch wieder nicht. (Und der Rest der Argumente von grux: Gleiche Syntax wie Smartpointer, man weiß wo das const hin muss? oO Und nach void* casten musste man noch nie.)

    Aber ich sage ja auch nichts gegen Smartpointer an sich, unique_ptr nutze ich überall, nur zum übergeben macht es keinen Sinn, wenn man keinen Besitz übergibt. Das Killerfeature von Smartpointern ist halt das sichere delete, aber wenn man das nicht braucht (weil man den Zeiger eh nicht besitzt), dann machen sie einfach keinen Sinn.



  • Nexus schrieb:

    Dobi schrieb:

    Wenn mich C++11-STL-Abhängigkeit nicht stört, und es nichts mit Performance zu tun hat, warum sollte ich dann nackte Zeiger incl. der dazugehörigen Gefahren benutzen?

    Weil dir weder unique_ptr noch shared_ptr was bringt, wenn du keinen Besitz zu verwalten hast. Wenn die Situation bei dir nicht vorkommt, ok 🙂

    In der Situation benutz ich halt ne Referenz. 😉

    cooky451 schrieb:

    Dobi schrieb:

    dazugehörigen Gefahren

    Die da wären? Ausversehen ++ schreiben?

    Memleaks oder Ungültigkeit. Aus void Foo( Irgendwas* ); geht ja nur mit Kommentar oder Verständnis für das, was passiert, hervor, ob der Besitz auch übergeben wird. Bei void Foo( Irgendwas& ); und void Foo( shared_ptr<Irgendwas> ); sieht jeder direkt, was da los ist.
    Für alles, das ich mir mit new hole, benutz ich RAII. Wenn ich dann sicher sein kann, dass das übergebene Objekt am Leben bleibt, übergeb ich es per Referenz. Wenn ich das nicht sein kann (Threadigkeit) per shared_ptr. Bei allen Beispielen, die mir einfallen, bei denen ich ein Objekt ohne den dazugehörigen Besitz übergebe, brauche ich keinen Zeiger, weil ich eine Referenz nehmen kann. Gibt es da irgendeinen Fall (kurzes Codebeispiel wär cool, bei dem void Foo( Irgendwas* ); nötig wäre? Ich schließ ja nicht aus, dass ich nicht irgendeine Anwendung gerade total übersehe.


Anmelden zum Antworten