Der Grund dafür, dass du einen unique_ptr nicht einfach so als Parameter übergeben kannst und einen shared_ptr schon, ergibt sich bereits aus dem Namen. Ein unique_ptr hat einen einzigen,
eindeutigen Besitzer (er setzt das Konzept durch, dass jede Ressource einem eindeutigen Besitzer zugeordnet ist, der für sie verantwortlich ist). Einen unique_ptr zu übergeben, bedeuetet, dass das Objekt seinen Besitzer wechselt. Ein Besitzerwechsel bedeutet wiederum, dass der alte Pointer ungültig werden muss (es kann nur einen Besitzer geben). Daher musst du so einen Transfer explizit mit std::move veranlassen:
Code:
unique_ptr<int> p1 = make_unique<int>(42);
unique_ptr<int> p2 = std::move(p1); // p1 nun ungültig
Wenn du den Pointer nur kurz "ausleihen" (d.h. die Funktion verwendet ihn, speichert ihn aber nirgendwo, weshalb es im Prinzip zu einem gegebenen Zeitpunkt weiterhin nur einen Besitzer gibt) möchtest, kannst du das mit const Referenzen machen:
Code:
void func (const unique_ptr<int> &ptr)
{
//hier kannst du das Objekt, auf das ptr zeigt, verwenden, aber es ihm nicht wegnehmen
//kopien von ptr sind somit nicht gestattet
}
// geht nun, weil func nur eine Referenz erwartet und somit nichts kopiert wird
func(ptr);
Hier ist die Thematik und die möglichen Alternativen noch mal etwas ausführlicher dargestellt:
[Only registered and activated users can see links. Click Here To Register...]
shared_ptr dagegen ist für einen geteilten Besitz gedacht. Es kann mehrere Besitzer für dieselbe Ressource geben, weshalb shared_ptr ein Kopieren erlaubt und du nicht auf expliziten Transfer oder Referenzen angewiesen bist. shared_ptr führt einen Referenzzähler, um festzuhalten, wie viele Besitzer es gibt. Erreicht der Zähler 0, wird das Objekt gelöscht.
Dieses Prinzip kommt einem Garbage Collector, wie man ihn aus C# oder Java kennt, sehr nahe, ist allerdings nicht exakt gleich. Ein shared_ptr gibt die Ressource nämlich sofort frei, wenn der Zähler 0 wird, während ein GC den Zeitpunkt der Freigabe etwas komplexer bestimmt. Außerdem kommt ein GC mit zirkulären Abhängigkeiten in der Objektstruktur klar, während du bei reiner Verwendung von shared_ptr damit ein Leak verursachen kannst (Objekt A hat einen Verweis auf B, weshalb der Zähler für B auf 1 bleibt, B hat einen Verweis auf A, weshalb dessen Zähler ebenfalls auf 1 bleibt => A und B werden nie gelöscht). Diese Kreise musst du mit Verwendung von weak_ptr explizit auflösen (du bestimmst also wieder einen eindeutigen Besitzer, der für die Löschung verantwortlich ist).
In der Regel ist unique_ptr zu bevorzugen, weil du dir ohnehin immer um das Konzept Besitz Gedanken machen musst. Ein shared_ptr nimmt dir diese Bürde wie gesagt nur teilweise ab. shared_ptr solltest du nur verwenden, wenn es einen wirklichen Bedarf dafür gibt, dass eine Ressource zwischen
mehreren Besitzer über einen längeren Zeitraum geteilt wird.