Einige Fragen zu Smartptr
-
Eisflamme schrieb:
Nutzt ihr Smartpointer anstatt von jedem Zeiger oder fallen euch Ausnahmen ein?
Ich nutze fast ausschliesslich Smart-Pointer. Wobei Smart-Pointer jetzt nicht automatisch shared_ptr bedeutet. scoped_ptr ist auch ein Smart-Pointer, sogar der konzeptionell fragwürdige auto_ptr ist ein Smart-Pointer. Interessant dass die Anti-shared_ptr Fraktion das wiedermal total ignoriert hat

Ausnahmen gibt es aber natürlich. z.B. wenn man Zeiger als schnelle Iteratoren über Arrays verwendet. Als Beispiel fallen mir ein: Software-Rendering, Low-Level String-Manipulation, Parser etc.
Wo ich kann versuche ich allerdings ganz auf Zeiger zu verzichten, seien sie nun "smart" oder nicht. z.B. indem ich Referenzen statt Zeigern übergebe.
Ich bin nicht ganz sicher, wann ich weak_ptr und wann shared_ptr benutzen sollte.
weak_ptr verwende ich fast nur um Zyklen aufzubrechen. Ganz ganz selten mal ohne dass es zu Zyklen kommen könnte, wenn z.B. ein Objekt ein anderes kennen soll, aber dessen Zerstörung nicht verhindern (weil das Objekt z.B. viel Resourcen verschlingt). Solche Fälle sind allerdings selten, und lassen sich dann auch oft eleganter lösen.
Was, wenn ich beispielsweise einer Funktion, die irgendwas macht, einen Zeiger übergeben möchte, der in der aufrufenden Funktion als shared_ptr bekannt ist?
Kommt drauf an.
Wenn die Funktion nicht "shared ownership" übernehmen muss, dann musst du keinen shared_ptr übergeben, es reicht eine Referenz.
Wenn die Funktion "shared ownership" übernehmen darf, dann übergibt einen "shared_ptr const&". weak_ptr macht IMO gar keinen Sinn.shared_ptr hat ja anscheinend schon ein bisschen zu tun, zählt intern Referenzen mit etc. Wenn ich da bei jedem Funktionsaufruf eine Instanz erstellen und danach zerstören lassen würde, wäre das evtl. Overhead, daher macht da für mich der weak_ptr mehr Sinn, oder?
weak_ptr hat gleich viel oder mehr Overhead. Du musst ja den weak_ptr erstmal locken bevor du ihn verwenden kannst. Dabei entsteht ein shared_ptr. Der muss auch irgendwie konstruiert und wieder zerstört werden.
Entweder du übergibst wie schon erwähnt eine Referenz, oder eine (const) Referenz auf den shared_ptr, oder ggf. noch einen rohen Pointer (macht IMO nur Sinn wenn der Zeiger null sein darf).BTW: der Referenz-Zähler wird - sofern die Boost mit Threading-Support konfiguriert ist - atomar inkrementiert und dekrementiert (-> Interlocked Instructions). 1x shared_ptr kopieren und gleich wieder zerstören kann da gleich mal 100+ Zyklen brauchen, auch wenn alles Inline erweitert wird. Und die meisten Compiler können Interlocked-Aufrufe auch nicht wegoptimieren, was die Sache doppelt schlimm macht

Wie nennt ihr eure typedefs, wenn ihr shared_- und weak_ptr nutzt?

Ich verwende meist gar keine typedefs.
Dort wo sie in unseren Projekten verwendet werden, heissen sietypederf boost::shared_ptr<Type> TypePtr;
-
Eisflamme schrieb:
- Lokal heisst innerhalb einer meiner Funktionen? Wo am Anfang das new steht und am Ende das delete? Das ist fuer mich per se aber dann auch kein Argument, es sei denn, man ist sich ueber das Exceptionverhalten der aufgerufenen Bibliotheksfunktion nicht sicher... aber das sollte man imo sowieso immer sein, oder?
Grundsätzlich gibt es zum scoped_ptr mehr als ein Argument. Das Exceptionverhalten ist eines davon, das andere ist das man unproblematisch ein return in eine Funktion bauen kann. Ich bin ein Favorit davon Funktionen so früh als möglich zu beenden (ist mir lieber als verschachtelte if-Konstrukte).
Eisflamme schrieb:
- Das mit den geteilten Verantwortlichkeiten verstehe ich eigentlich auch nicht mehr so ganz. Ich wuerde fast immer dafuer sorgen, dass irgend ein Objekt eben die Hauptverantwortlichkeit traegt, sonst fliegt ein Zeiger ja irgendwie random im Raum rum. Hat jemand dafuer ein Beispiel?
Wenn du genau das hast: Ein Objekt trägt die Hauptverantwortung, dann sind shared_ptr fehl am Platz und ptr-Container besser.
Ein Beispiel für den Einsatz von einem shared_ptr könnte z.B. sein, wenn zwei nicht modale Masken auf gleiche Daten zugreifen sollen, aber nicht klar ist, welche zuerst geschlossen wird. Wenn beide die Daten per shared_ptr halten, ist sichergestellt, das die Daten erst mit der letzten gelöscht werden.
Eisflamme schrieb:
- Ist es dann ratsam immer die ptr-Container zu nehmen, wenn ich einen Container mit Objektzeigern (wie bei meinem Model) nutze? Oder gibt es auch hier nicht auf den ersten Blick ersichtliche Nachteile?
Ich weiß nicht ob das inzwischen geändert wurde (wir haben hier eine ältere Boost-Bibliothek im Einsatz), aber die Schnittstellen der ptr-Container haben sich imho nicht mit allen STL-Konstrukten vertragen (was aber nur selten bei mir zum tragen kam).