Sydius hat die Typen recht gut umrissen:
- Normale Zeiger sind genau das - sie verweisen auf etwas, das sich irgendwo im Speicher befindet. Wem gehört es? Das verraten nur die Kommentare. Wer gibt es frei? Irgendwann hoffentlich der Besitzer.
- Intelligente Zeiger sind ein Sammelbegriff, der viele Typen abdeckt; ich nehme an, Sie meinten scoped pointer, der die RAII Muster. Es handelt sich um ein Stack-Objekt, das einen Zeiger umhüllt; wenn es den Gültigkeitsbereich verlässt, ruft es delete für den Zeiger auf, den es umhüllt. Es "besitzt" den enthaltenen Zeiger insofern, als es dafür verantwortlich ist, ihn zu einem bestimmten Zeitpunkt zu löschen. Sie ermöglichen es, einen Rohverweis auf den Zeiger zu erhalten, den sie umhüllen, um ihn an andere Methoden zu übergeben, sowie Freisetzung von den Zeiger, so dass er in den Besitz einer anderen Person übergeht. Es ist nicht sinnvoll, sie zu kopieren.
- Gemeinsam genutzte Zeiger ist ein auf einem Stapel zugewiesenes Objekt, das einen Zeiger umhüllt, so dass man nicht wissen muss, wem er gehört. Wenn der letzte gemeinsam genutzte Zeiger für ein Objekt im Speicher vernichtet wird, wird auch der umhüllte Zeiger gelöscht.
Und wann sollten Sie sie einsetzen? Sie werden entweder stark von "scoped pointers" oder "shared pointers" Gebrauch machen. Wie viele Threads laufen in Ihrer Anwendung? Wenn die Antwort "potenziell viele" lautet, können sich gemeinsam genutzte Zeiger als Leistungsengpass erweisen, wenn sie überall eingesetzt werden. Der Grund dafür ist, dass das Erstellen/Kopieren/Destruieren eines gemeinsam genutzten Zeigers ein atomarer Vorgang sein muss, und das kann die Leistung beeinträchtigen, wenn viele Threads ausgeführt werden. Dies wird jedoch nicht immer der Fall sein - nur durch Testen können Sie dies mit Sicherheit feststellen.
Es gibt ein Argument (das mir gefällt) gegen gemeinsam genutzte Zeiger - wenn man sie verwendet, können Programmierer ignorieren, wem ein Zeiger gehört. Dies kann zu kniffligen Situationen mit zirkulären Verweisen führen (Java erkennt diese, aber Shared Pointer nicht) oder zu allgemeiner Faulheit der Programmierer in einer großen Codebasis.
Es gibt zwei Gründe für die Verwendung von scoped pointers. Der erste ist für einfache Ausnahmesicherheit und Bereinigungsoperationen - wenn Sie garantieren wollen, dass ein Objekt angesichts von Ausnahmen auf jeden Fall bereinigt wird, und Sie dieses Objekt nicht auf dem Stack allozieren wollen, legen Sie es in einen scoped pointer. Wenn die Operation erfolgreich ist, können Sie es in einen gemeinsamen Zeiger übertragen, aber in der Zwischenzeit sparen Sie den Overhead mit einem scoped pointer.
Der andere Fall ist, dass Sie eine klare Objektverantwortung wünschen. Manche Teams bevorzugen dies, manche nicht. Zum Beispiel kann eine Datenstruktur Zeiger auf interne Objekte zurückgeben. Bei einem "scoped pointer" würde ein "raw pointer" oder ein Verweis zurückgegeben, der als "weak reference" behandelt werden sollte - es ist ein Fehler, auf diesen Zeiger zuzugreifen, nachdem die Datenstruktur, der er gehört, zerstört wurde, und es ist ein Fehler, ihn zu löschen. Bei einem gemeinsam genutzten Zeiger kann das besitzende Objekt die internen Daten, die es zurückgegeben hat, nicht zerstören, wenn jemand noch ein Handle darauf hält - dies könnte Ressourcen viel länger als nötig offen lassen, oder je nach Code noch viel schlimmer.