2014-04-07 6 views
7

Das erste Mal habe ich versucht, einen Bereich für Schleife basierend zu schreiben über unique_ptrs iterieren schrieb ich:Wie ein unique_ptr, dessen Zeiger und Daten zu schreiben, ist const

std::vector<std::unique_ptr<Foo>> vec; 
// Initialize vec 

for (auto v : vec) // error 
{} 

Ich erkannte dann diese eine Kopie zu erstellen versucht, jedes Elements, das mit einem unique_ptr keinen Sinn ergibt. Also schrieb ich es als eine Referenz:

for (auto& v : vec) 
{} 

Das Hinzufügen einer Const davor hält mich davon ab, den Zeiger zu ändern.

for (const auto& v : vec) 
{ 
    v = nullptr; // error (good!) 
} 

Wie kann ich es schreiben, so dass die angezeigten Daten nicht geändert werden können? Zum Beispiel sollte der folgende Code nicht kompiliert werden.

for (??? v : vec) 
{ 
    v->func(); 
} 

class Foo 
{ 
public: 
    void func(); 

private: 
    bool mBar; 
} 

Foo::func() 
{ 
    mbar = true; // Should cause error 
} 
+0

Müssen Sie immer den Pointee "const" (und damit die Definition von 'vec' ändern) oder brauchen Sie nur für diese Schleife * const' *? –

+0

Eine andere Anwendung könnte das Schreiben einer Inspektorfunktion sein, also vorzugsweise nur für die Schleife. Aus den Antworten klingt dies jedoch nicht möglich. – user870130

+0

siehe hier: http://stackoverflow.com/questions/15518894/forcing-use-of-cbegin-cend-in-range-based-for – user1095108

Antwort

5

Um die Daten vor Veränderungen, umfassen const in der Template-Parameter für Ihren Zeiger zu verhindern:

std::vector<std::unique_ptr<const Foo>> vec; 

Ich glaube, Sie Probleme machen den Zeiger selbst const obwohl haben werden. Der Grund ist, dass der Vektor in der Lage sein muss, das Zeigerobjekt intern zu kopieren (z. B. wenn die Größe des Containers geändert wird). Bei einem unique_ptr bedeutet dies, dass das Eigentum zwischen den Instanzen übertragen werden muss, was bedeutet, dass es veränderbar sein muss (nicht const).

Um den Zeiger selbst const, Ich denke, Sie haben zwei Hauptmöglichkeiten: Verwenden Sie einen Vektor von const shared_ptr<> oder ein Array (d. H. Feste Größe) von const unique_ptr<>.

3

Dafür Ihre unique_pointer müssen für eine const, Qualifiziert Art, wie diese instanziert werden:

std::vector<std::unique_ptr<const Foo>> vec; 

Aber vielleicht ist es genug, um den Iterator zu verwenden, um eine konstante Referenz zu Beginn initialisieren Die Schleife sollte der Compiler optimieren:

for (const auto& v_iter : vec) { 
    const auto& x = *v_iter; 
    do_things(...); 
} 

Alles andere ist Hacker.

Was würde wahrscheinlich funktionieren wird Ihre vector<unique_pointer<Foo>> als ein vector<unique_pointer<const Foo>> reinterpreting, aber es könnte in hilarious undefinierten Verhalten führen, wenn entweder vector oder unique_pointer eine Spezialisierung hat. Versuchen Sie nicht, das ist es nicht wert.