Ich bin ziemlich neu in den C ++ 11 Smartpointern, und ich versuche, sie effektiv in einem Projekt zu verwenden. In meinem Projekt habe ich viele Funktionen, die eine konstante Referenz auf ein vector
von unique_ptr
nehmen, einige Berechnungen darauf durchführen und einige Ergebnisse in einen Rückgabeparameter wie folgt einfügen:
Ich verwende unique_ptr
, weil die Prozedur, die all diese Funktionen aufruft, der einzige Eigentümer der Objekte in vector
ist und die Funktionen die Objekte nur "ausleihen", um sie als Eingabe zu lesen.
Nun versuche ich, eine Funktion zu schreiben, die Berechnungen auf verschiedenen Teilmengen des vector
durchführt, und um dies zu tun, muss es verschiedene "Versionen" von vector
haben, die diese Teilmengen in der richtigen Reihenfolge enthalten an eine weitere Funktion übergeben, die ein vector<unique_ptr<Scalar>>
als Eingabe verwendet. Aber die einzige Möglichkeit, eine Teilmenge eines Vektors zu erhalten, besteht darin, eine Kopie davon zu erstellen - was ein Problem ist, weil unique_ptr
s nicht kopiert werden kann. Ich möchte, dass der Code in etwa so aussieht:
Natürlich funktioniert das nicht. Ich könnte es funktionieren lassen, wenn ich das unique_ptr
s durch shared_ptr
s ersetze, aber das hat zwei Probleme:
computeOnSubsets
teile, und ich nicht; der Anrufer ist immer noch der alleinige Besitzer. (Ich habe gelesen, dass shared_ptr
bedeutet, dass Sie das Eigentum mit allem teilen, das eine Kopie davon hat). vector<shared_ptr<Scalar>>
zu ändern. Ich möchte nur eine temporäre, schreibgeschützte Kopie eines Zeigers erstellen, um temporäre, schreibgeschützte Untervektoren zu machen. Gibt es eine Möglichkeit, dies zu tun? weak_ptr
klingt wie das, was ich brauche (nicht besitzender temporärer Zeiger), aber es kann nur mit shared_ptr
verwendet werden.
Ich benutze unique_ptr, weil die Prozedur, die all diese Funktionen aufruft, der einzige Eigentümer der Objekte im Vektor ist und die Funktionen nur die Objekte "ausleihen", um sie als Eingabe zu lesen.
Da die Rechenfunktionen nicht die spitzen Objekte besitzen, sondern nur deren Zustand beobachten und Berechnungen durchführen, sollten Sie ihnen einen Vektor von Beobachtungszeigern (in diesem Fall regulären rohen Zeigern <) übergeben / strong>), anstelle eines Vektors von unique_ptr
s.
Da computeOnAllSubsets()
und computeOnSet()
nicht für die Lebensdauer der Scalar
-Objekte verantwortlich sind, sollten sie nicht einmal Eigentümer werden - sie sollten also nicht das besitzende unique_ptr
s erhalten.
Immerhin wird durch die Logik Ihres Programms garantiert, dass diese Funktionen keine freien Referenzen erhalten, weil die Eigentümerfunktion ihren Vektor nicht zerstören wird, bevor sie alle notwendigen Berechnungen durchgeführt hat. Dies wird direkt von dem, was Sie schreiben, unterstützt:
Ich möchte nur eine temporäre, schreibgeschützte Kopie eines Zeigers machen, nur um temporäre, schreibgeschützte Untervektoren zu erstellen. Gibt es eine Möglichkeit, dies zu tun?
Übergeben Sie einfach einen Vektor von rohen Zeigern an Ihre Rechenfunktionen . Bei einem unique_ptr
erhalten Sie Zugriff auf den eingekapselten rohen Zeiger, indem Sie die Elementfunktion get()
:
Als Alternative zu rohen Zeigern können Sie std::reference_wrapper
zum Versenden von Referenzobjekten verwenden . Insbesondere während des Umgestaltens einer Legacy-Code-Basis, wo rohe Zeiger für die manuelle Speicherverwaltung verwendet werden, würde dies deutlich machen, dass das Eigentum der referenzierten Objekte woanders liegt.
Beachten Sie jedoch, dass ein roher Zeiger in Modern C ++ meistens ein Synonym zum Beobachten von Zeigern ist, daher ist die obige Unterscheidung in einem verallgemeinerten Kontext nicht wirklich sinnvoll. Der Anwendungsfall, für den std::reference_wrapper
grundlegend ist, ist, wenn Sie Objekte anhand einer Funktionsvorlage übergeben möchten, die ihre Argumente nach Wert annimmt ( std::bind()
ist ein typisches Beispiel).
Wenn Sie einen Iterator verwenden, wird Ihr Code möglicherweise wesentlich allgemeiner. Erklären Sie einfach Ihre Berechnungsfunktion wie folgt:
%Vor% Diese Berechnungsfunktionsvorlage verarbeitet Daten im Bereich [first_it, last_it)
und setzt das Ergebnis dann in [d_first, d_last)
. Die Art der Eingabe- oder Ausgabebehälter ist nicht wichtig. Die Iteratoren fungieren als Zeiger auf die Elemente im Container, was der Gedanke von STL ist.
Außerdem gehen Sie in einigen Fällen nicht manuell durch den Bereich. Verwenden Sie einfach Funktionsvorlagen in <algorithm>
, z. B. std::for_each
und std::transform
.
Ich verstehe das Code-Snippet in computeOnAllSubsets
nicht wirklich, aber instinktiv denke ich, dass std::transform
hilfreich sein könnte.
Tags und Links c++ c++11 unique-ptr shared-ptr stdvector