Temporäre schreibgeschützte Kopie von unique_ptr

8

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:

%Vor%

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:

%Vor%

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:

  • Es würde philosophisch bedeuten, dass ich den Besitz des Sets mit der Funktion 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).
  • Es würde den Overhead des Referenzzählens einführen, sogar an Stellen, wo ich es nicht brauche, weil es mich zwingen würde, den Eingabeparameter aller meiner Methoden in 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.

    
Edward 08.04.2013, 19:46
quelle

2 Antworten

9
  

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() :

aufrufen %Vor%

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).

    
Andy Prowl 08.04.2013, 19:56
quelle
2

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.

    
Matt Yang 09.04.2013 09:09
quelle