Speicherleck trotz smart-pointer
-
Eventuell hilft dir std::weak_ptr. Einen shared Pointer und einen raw Pointer auf das selbe Objekt zu haben ist potenziell gefaehrlich, da das Objekt deallocated werden kann. Dann hast du einen dangling raw Pointer. Mit
std::weak_ptr
tritt dieses Problem nicht auf.Manchmal ist aber ein raw Pointer durchaus die richige Wahl.
-
icarus2 schrieb:
Manchmal ist aber ein raw Pointer durchaus die richige Wahl.
Wann denn?
-
Artchi schrieb:
icarus2 schrieb:
Manchmal ist aber ein raw Pointer durchaus die richige Wahl.
Wann denn?
Raw Pointer sind z.B. als Funktionsargumente durchaus sinnvoll.
-
axels. schrieb:
Nur, warum entsteht trotzdem ein Speicherleck?
Steht zwar schon da, aber zur Erläuerung:
https://visualstudiomagazine.com/articles/2012/10/19/circular-references.aspx
-
Artchi schrieb:
icarus2 schrieb:
Manchmal ist aber ein raw Pointer durchaus die richige Wahl.
Wann denn?
Wenn man viel mit Frameworks arbeitet, die hundert Jahre alt sind und keinen Smart-Pointer-Support haben, Besitz transferieren und generell schlecht designed sind. In dem Fall muss man sich nicht quälen, finde ich. Ansonsten fällt mir in C++ >11 auch nichts mehr ein, denn für jeden erdenklichen Fall sind passende Pointer-Templates da und man hat dadurch wenig bis gar keinen Overhead.
-
goi schrieb:
Artchi schrieb:
icarus2 schrieb:
Manchmal ist aber ein raw Pointer durchaus die richige Wahl.
Wann denn?
Wenn man viel mit Frameworks arbeitet, die hundert Jahre alt sind und keinen Smart-Pointer-Support haben, Besitz transferieren und generell schlecht designed sind. In dem Fall muss man sich nicht quälen, finde ich. Ansonsten fällt mir in C++ >11 auch nichts mehr ein, denn für jeden erdenklichen Fall sind passende Pointer-Templates da und man hat dadurch wenig bis gar keinen Overhead.
Ja, und wenn man sich dann in einem Graph bewegt (wie es hier ja der Fall zu sein scheint) erzeugt man bei jedem Schritt aus einem weak_ptr erst mal einen shared_ptr (inklusive Threadsynchronisation) um einfach nur einen Pointer zu dereferenzieren. Es gibt das schöne Sprichwort "das Kind mit dem Bad ausschütten" - das passt hier sehr gut. Pointer sind gut! Es müssen nicht alle Pointer durch Smartpointer ersetzt werden. Wenn man Angst davor hat, sollte man eine Sprache wie Java mit Garbage Collection wählen.
-
Garbage collection hilft hier nicht, denn die hat genau mit den gleichen Problemen zu kämpfen.
Man muss natürlich immer für konkrete Anwendungen und typische Problemgrößen überlegen was man tut, aber das muss man mit raw-Pointern auch. Und wenn man von der Struktur her schon zyklische Referenzen zu befürchten hat, außerdem nachgemessen hat, dass die weak-Pointer merkliche Einbußen verursachen, dann kann man in seiner Datenstruktur schauen, dass man mit raw-Pointern arbeitet. Aber die schreibt man in der Regel nur einmal, dokumentiert sie ordentlich und versieht sie mit Unit-Tests. Oft gibt es z.B. in boost auch fertige Templates für die zugrunde liegenden Strukturen, die man stattdessen einfach verwenden kann.
Im alltäglichen Gebrauch dagegen bilden die Smart-Pointer schön ab, was sich der Entwickler dabei gedacht hat und das dokumentiert indirekt sogar auch noch den Code. Nicht selten bauen Entwickler, die Performance optimieren wollen, intern wieder Smart-Pointer-Logik nach und machen dabei einen schlechteren Job als die Library bzw. der Compiler.
Lange Rede kurzer Sinn: wenn der OP sein Problem gelöst hat und Performanceschwierigkeiten hat, dann kann man das hier diskutieren. Ansonsten sind raw-Pointer eher schwierig zu handhaben und daher nicht das Mittel erster Wahl. Ich persönlich verwende sie nur intern, wenn die STL und boost nicht die passende Template-Struktur liefern, aber das wir immer seltener.
-
Auch bei GC gibt es Speicherlecks, wenn man zyklische Abhängigkeiten hat. Und natürlich gibt es auch in den GC-Sprachen Weak-Referenzen:
Java: https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html
C#: https://msdn.microsoft.com/de-de/library/system.weakreference(v=vs.110).aspx
Python: https://docs.python.org/2/library/weakref.htmlUnd wenn es angeblich in den GC-Sprachen keine Speicherlecks geben soll, frage ich mich, warum es für diese so viele Memory-Profiler-Tools gibt?
-
goi schrieb:
Garbage collection hilft hier nicht, denn die hat genau mit den gleichen Problemen zu kämpfen.
Nein, hat sie nicht
goi schrieb:
Im alltäglichen Gebrauch dagegen bilden die Smart-Pointer schön ab, was sich der Entwickler dabei gedacht hat
Wenn der Entwickler an Besitz gedacht hat, ja. Wenn es nicht um Besitz geht haben Smartponter keie Berechtigung. Der Iterator eines std::vector hat gefälligst ein Raw Pointer zu sein und nicht ein zeitfressendes Smartgedöns. Eine Funktion, die nicht den Besitz an einem Objekt übernimmt, braucht als Datentyp keine Smart Pointer - auch nicht als const Referrenz.
goi schrieb:
Ansonsten sind raw-Pointer eher schwierig zu handhaben und daher nicht das Mittel erster Wahl. Ich persönlich verwende sie nur intern, wenn die STL und boost nicht die passende Template-Struktur liefern, aber das wir immer seltener.
Jeder kann seine persönlichen Ansichten haben. Wenn er sie aber in einem Forum als Regel aufstellt muss er sich auch auf Widerstand gefasst machen.
Raw Pointer sind gut, wenn man tatsächlich Pointer braucht (eine Referenz oder std::optional sind oft die besseren Alternativen). Besitzende Raw Pointer sollte man wo möglich vermeiden.
-
Artchi schrieb:
Auch bei GC gibt es Speicherlecks, wenn man zyklische Abhängigkeiten hat.
Den GC in einer verbreiteten Sprach im Jahr 2017 möchte ich sehen, der keine Zyklen auflösen kann.
Artchi schrieb:
Und natürlich gibt es auch in den GC-Sprachen Weak-Referenzen:
Hat hier irgendwo irgendjemand etwas gegenteiliges behauptet? Hat hier irgendwo irgendjemand behauptet, weak_ptr seinen komplett nutzlos?
Artchi schrieb:
Und wenn es angeblich in den GC-Sprachen keine Speicherlecks geben soll, frage ich mich, warum es für diese so viele Memory-Profiler-Tools gibt?
Und hast du auch versucht, eine Antwort auf diese Frage zu finden?
Mit einem GC gibt es kein Memory Leak! Aber selbstverständlich gibt es ständig die Fälle, dass irgendwo, vielleicht in einem Callback, noch eine Referenz auf die 3GB vorhanden ist, die das Programm ums verrecken nicht freigeben will (das kann man sich mit Lambda und shared_ptr in C++ übrigens auch wunderbar einhandeln). Eine Lösung für das Problem kann dann sogar einer der von dir zitierten Weakpointer sein.
-
manni66 schrieb:
Artchi schrieb:
Auch bei GC gibt es Speicherlecks, wenn man zyklische Abhängigkeiten hat.
Den GC in einer verbreiteten Sprach im Jahr 2017 möchte ich sehen, der keine Zyklen auflösen kann.
Also selbst ein GC, der mit Reference Counting arbeitet, löst dieses Problem. Es ist ja auch öfters in C++ der Fall, dass ein zyklischer shared_pointer keine Probleme macht, bis eine besodnere Kosntellation eintritt, die erst das Leck erzeugt. Deswegen sind diese Fehler ja auch nicht ganz trivial.
manni66 schrieb:
Artchi schrieb:
Und wenn es angeblich in den GC-Sprachen keine Speicherlecks geben soll, frage ich mich, warum es für diese so viele Memory-Profiler-Tools gibt?
Und hast du auch versucht, eine Antwort auf diese Frage zu finden?
Mit einem GC gibt es kein Memory Leak! Aber selbstverständlich gibt es ständig die Fälle, dass irgendwo, vielleicht in einem Callback, noch eine Referenz auf die 3GB vorhanden ist, die das Programm ums verrecken nicht freigeben will (das kann man sich mit Lambda und shared_ptr in C++ übrigens auch wunderbar einhandeln). Eine Lösung für das Problem kann dann sogar einer der von dir zitierten Weakpointer sein.Ich persönlich benenne diesen Fall eher ungern als Memory Leak, weil es faktisch eben keins ist. Es wird halt nur Speicher verbraten, der eigentlich nicht mehr gebraucht wird, aber da könnte man argumentieren, dass der Entwickler das so will, sonst hätte er anders programmiert.
-
manni66 schrieb:
goi schrieb:
Garbage collection hilft hier nicht, denn die hat genau mit den gleichen Problemen zu kämpfen.
Nein, hat sie nicht
goi schrieb:
Im alltäglichen Gebrauch dagegen bilden die Smart-Pointer schön ab, was sich der Entwickler dabei gedacht hat
Wenn der Entwickler an Besitz gedacht hat, ja. Wenn es nicht um Besitz geht haben Smartponter keie Berechtigung. Der Iterator eines std::vector hat gefälligst ein Raw Pointer zu sein und nicht ein zeitfressendes Smartgedöns. Eine Funktion, die nicht den Besitz an einem Objekt übernimmt, braucht als Datentyp keine Smart Pointer - auch nicht als const Referrenz.
goi schrieb:
Ansonsten sind raw-Pointer eher schwierig zu handhaben und daher nicht das Mittel erster Wahl. Ich persönlich verwende sie nur intern, wenn die STL und boost nicht die passende Template-Struktur liefern, aber das wir immer seltener.
Jeder kann seine persönlichen Ansichten haben. Wenn er sie aber in einem Forum als Regel aufstellt muss er sich auch auf Widerstand gefasst machen.
Raw Pointer sind gut, wenn man tatsächlich Pointer braucht (eine Referenz oder std::optional sind oft die besseren Alternativen). Besitzende Raw Pointer sollte man wo möglich vermeiden.
Willst Du einfach nur diskutieren? Lies was ich geschrieben habe und dann sag mir wo das im Gegensatz zu dem steht was Du sagst
. Natürlich soll ein std::vector intern mit Raw-Pointern arbeiten. Das ist eine Brot und Butter Struktur die gefälligst funktionieren soll. In den restlichen 99% sind Smart-Pointer oder - wie Du selber sagst - je nach Szenario Referenzen oder Optionals einfach empfehlenswerter, es sei denn man will heimlich C programmieren. Den Strohmann von wegen man soll alles krampfhaft in Smart-Pointer-Logik verpacken, kannst Du Dir an den Hut stecken, hab ich nie gesagt.