Ich habe einen erweiterbaren C ++ - Wrapper um eine sehr schwer zu verwendende, aber auch sehr nützliche C-Bibliothek geschrieben. Das Ziel ist es, c ++ für die Zuweisung des Objekts, die Offenlegung seiner Eigenschaften, die Freigabe des Objekts, das Kopieren der Semantik usw. zu nutzen.
Das Problem ist folgendes: Manchmal möchte die c-Bibliothek das zugrunde liegende Objekt (einen Zeiger auf das Objekt), und der Klassendestruktor sollte den zugrunde liegenden Speicher nicht zerstören. Während der meisten Zeit sollte der Destruktor die Zuordnung des zugrunde liegenden Objekts aufheben. Ich habe mit dem Setzen eines bool hasOwnership
Flags in der Klasse experimentiert, damit der Destruktor, der Zuweisungsoperator usw. weiß, ob er den zugrunde liegenden Speicher freigeben soll oder nicht. Dies ist jedoch für den Benutzer umständlich, und manchmal gibt es auch keine Möglichkeit zu wissen, wann ein anderer Prozess diesen Speicher verwendet.
Derzeit habe ich es so eingerichtet, dass ich das hasOwnership-Flag setze, wenn die Zuweisung von einem Zeiger des gleichen Typs wie der zugrunde liegende Typ stammt. Ich mache dasselbe, wenn der überladene Konstruktor mit dem Zeiger aus der c-Bibliothek aufgerufen wird. Dies ist jedoch immer noch nicht der Fall, wenn der Benutzer das Objekt erstellt und an eine meiner Funktionen übergeben hat, die c_api aufruft und die Bibliothek den Zeiger zur späteren Verwendung speichert. Wenn sie ihr Objekt löschen würden, würde dies zweifellos einen Segfault in der c-Bibliothek verursachen.
Gibt es ein Entwurfsmuster, das diesen Prozess vereinfachen würde? Vielleicht eine Art Referenzzählung?
quelle
unique_ptr
In den meisten Fällen kann diese Art von Ressourcen bereits verarbeitet werden, sodass Sie die Ressourcenverwaltung nicht selbst implementieren müssen.unique_ptr
verwendet dierelease
Methode, um das Eigentum an dem gespeicherten Objekt aufzugeben.Antworten:
Wenn sich die Verantwortung für das Bereinigen dynamisch zugeordneter Inhalte zwischen Ihrer Wrapper-Klasse und der C-Bibliothek ändert, je nachdem, wie die Dinge verwendet werden, haben Sie es entweder mit einer schlecht gestalteten C-Bibliothek zu tun oder Sie versuchen, in Ihrer Wrapper-Klasse zu viel zu tun.
Im ersten Fall können Sie nur nachverfolgen, wer für die Bereinigung verantwortlich ist, und hoffen, dass keine Fehler gemacht werden (weder von Ihnen noch von den Betreuern der C-Bibliothek).
Im zweiten Fall sollten Sie Ihr Wrapper-Design überdenken. Gehören alle Funktionen zu derselben Klasse oder können sie in mehrere Klassen aufgeteilt werden? Möglicherweise verwendet die C-Bibliothek etwas Ähnliches wie das Facade-Entwurfsmuster, und Sie sollten eine ähnliche Struktur in Ihrem C ++ - Wrapper beibehalten.
Selbst wenn die C-Bibliothek für die Bereinigung einiger Dinge verantwortlich ist, ist es auf keinen Fall falsch, einen Verweis / Zeiger auf diese Dinge zu behalten. Sie müssen sich nur daran erinnern, dass Sie nicht dafür verantwortlich sind, das zu bereinigen, worauf sich der Zeiger bezieht.
quelle
Oft können Sie ein Muster wie das folgende verwenden:
Durch die Verwendung können
release
Sie das Eigentum explizit übertragen. Dies ist jedoch verwirrend und sollte nach Möglichkeit vermieden werden.Die meisten C-Bibliotheken haben einen C ++ - ähnlichen Objektlebenszyklus (Objektzuweisung, Zugriffsmethoden, Zerstörung), der ohne Eigentumsübertragung gut auf das C ++ - Muster abgebildet werden kann.
Wenn Benutzer eine gemeinsame Eigentümerschaft benötigen, sollten sie diese
shared_ptr
für Ihre Klassen verwenden. Versuchen Sie nicht, eine Eigentumsfreigabe selbst zu implementieren.Update: Wenn Sie die Übertragung des Eigentums expliziter gestalten möchten, können Sie ein Referenzqualifikationsmerkmal verwenden:
Dann müssen Benutzer folgende
bar
Werte aufrufen:quelle
unique_ptr
, wird der darin enthaltene Zeiger nicht mehr gespeichert. Die Modellierung der Eigentumsübertragung und gleichzeitig die Ermöglichung des Zugriffs auf nicht genutzte Ressourcen scheint für Benutzer ziemlich verwirrend zu sein. Wie steuern Sie, wann die C-Bibliothek die Objekte freigibt, die sie jetzt besitzt?Es gibt eine einfache Antwort auf Ihr Problem, intelligente Zeiger. Wenn Sie einen intelligenten Zeiger verwenden, um den Speicher der C-Bibliothek zu speichern, und eine Referenz hinzufügen, wenn sich der Zeiger ebenfalls in der Bibliothek befindet (und die Referenz löschen, wenn die C-Bibliothek zurückkehrt), wird der Speicher automatisch freigegeben, wenn der Referenzzähler auf Null fällt (und nur dann)
quelle
Wenn die Bibliothek Dinge intern freigeben kann und die Szenarien, in denen dies geschehen kann, gut dokumentiert sind, können Sie nur ein Flag setzen, wie Sie es bereits tun.
quelle