2014-04-07 3 views
7

La prima volta che ho provato a scrivere una gamma basata ciclo for per iterare su unique_ptrs ho scritto:Come scrivere un unique_ptr cui puntatore e dei dati è const

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

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

Mi resi conto allora questo sta cercando di creare una copia di ogni elemento che non ha senso con un unique_ptr. Quindi l'ho scritto come riferimento:

for (auto& v : vec) 
{} 

Aggiungere un const di fronte a esso non mi impedisce di cambiare il puntatore.

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

Come posso scriverlo, in modo che i dati indicati non possano essere modificati? Ad esempio, il seguente codice non dovrebbe essere compilato.

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

class Foo 
{ 
public: 
    void func(); 

private: 
    bool mBar; 
} 

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

Hai sempre bisogno che il pointee sia 'const' (e quindi possa modificare la definizione di' vec') o hai solo bisogno che sia 'const' * per questo ciclo *? –

+0

Un'altra applicazione potrebbe essere la scrittura di una funzione di controllo, quindi preferibilmente solo per il ciclo. Tuttavia, dalle risposte questo non sembra possibile. – user870130

+0

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

risposta

5

Per evitare che i dati vengano modificati, includere const nel parametro modello per il puntatore:

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

penso che avrai problemi rendendo il puntatore stesso const però. Il motivo è che il vettore deve essere in grado di copiare l'oggetto puntatore attorno internamente (ad es. Quando il contenitore viene ridimensionato). Con un unique_ptr, significa che la proprietà deve essere trasferita tra le istanze, il che significa che deve essere mutabile (non const).

per rendere il puntatore stesso const, penso che hai due scelte principali: utilizzare un vettore di const shared_ptr<>, o un array (cioè dimensione fissa) di const unique_ptr<>.

3

Per questo, il vostro unique_pointer deve essere istanziato per un tipo Qualificato const, in questo modo:

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

Ma forse è sufficiente utilizzare l'iteratore per inizializzare un riferimento costante a inizio il loop, il compilatore dovrebbe ottimizzare via:

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

Tutto il resto è aggiustamenti.

Ciò che probabilmente avrebbe funzionato sta reinterpretando il tuo vector<unique_pointer<Foo>> come vector<unique_pointer<const Foo>>, ma potrebbe causare un comportamento indefinito esilarante se uno o vectorunique_pointer ha una specializzazione. Non provare, non ne vale la pena.