2011-11-23 17 views
20

¿Cómo se accede a los elementos unique_ptr de un contenedor (a través de un iterador) sin quitarle la propiedad al contenedor? Cuando uno obtiene un iterador para un elemento en el contenedor, ¿la propiedad del elemento aún está en el contenedor? ¿Qué tal si uno descuenta el iterador para obtener acceso al unique_ptr? ¿Eso realiza un movimiento implícito de unique_ptr?Iteración sobre un contenedor de unique_ptr's

Me parece que estoy usando shared_ptr mucho cuando necesito almacenar elementos en un contenedor (no por valor), incluso si el contenedor posee los elementos conceptualmente y el otro código simplemente desea manipular elementos en el contenedor, porque Tengo miedo de no poder acceder realmente a los elementos uniqueptr en el contenedor sin que se le quite la propiedad.

¿Algún conocimiento?

Respuesta

13

Siempre y cuando no intente hacer una copia del unique_ptr, puede usarlo. Tendrás que "desreferencia doble" del iterador para obtener el valor del puntero, tal como lo harías con shared_ptr. He aquí un breve ejemplo:

#include <vector> 
#include <memory> 
#include <iostream> 

template <class C> 
void 
display(const C& c) 
{ 
    std::cout << '{'; 
    if (!c.empty()) 
     std::cout << *c.front(); 
    for (auto i = std::next(c.begin()); i != c.end(); ++i) 
     std::cout << ", " << **i; 
    std::cout << "}\n"; 
} 

int main() 
{ 
    typedef std::unique_ptr<int> Ptr; 
    std::vector<Ptr> v; 
    for (int i = 1; i <= 5; ++i) 
     v.push_back(Ptr(new int(i))); 
    display(v); 
    for (auto i = v.begin(); i != v.end(); ++i) 
     **i += 2; 
    display(v); 
} 

Si lo hace (accidentalmente) crea una copia de la unique_ptr:

Ptr p = v[0]; 

continuación, usted encontrará a cabo en tiempo de compilación. No causará un error de tiempo de ejecución. Su caso de uso es por qué se construyó container<unique_ptr<T>>. Las cosas solo deberían funcionar, y si no lo hacen, el problema aparece en tiempo de compilación en lugar de tiempo de ejecución. Así que codifique y si no comprende el error de tiempo de compilación, haga otra pregunta aquí.

+0

Bien, creo que eso me aclara las cosas. He tenido la costumbre de usar la nueva función for_each con un lambda cuyo parámetro es el elemento pasado por valor, NO por referencia, pero supongo que tendré que hacer referencia a los elementos unique_ptr si quiero evitar un intento copiar/mover. PD si desreferencia el iterador una vez, y tomar una referencia a ese resultado, supongo que esto evita una copia intentada? Quiero decir como: 'for (Container :: iterator it = container.begin(); it! = Container.end(); it ++) { unique_ptr & element = &*it; // ¿No ha intentado copiar? } ' Gracias Howard, por cierto. –

+0

Sí, creo que debería funcionar bien. Aunque tienes un 'y' extra en tu código. Pero el compilador te dirá dónde. –

+0

Debería poder desreferenciarlo a a: blah & element = ** it; Todavía sin una copia, creo. (Probablemente más útil). –

32

Con auto y la basada en el rango de-bucles de C++ 11 este se vuelve relativamente elegante:

std::vector< std::unique_ptr<YourClass>> pointers; 
for(auto&& pointer : pointers) { 
    pointer->functionOfYourClass(); 
} 

La referencia a la &std::unique_ptr evita la copia y se puede utilizar el uniqe_ptr sin eliminación de referencias.

+0

¿Alguien sabe si hay una diferencia entre usar 'auto &' y 'auto &&' en este caso? Esta referencia sugiere el doble & http://en.cppreference.com/w/cpp/language/range-for, ambos parecen compilar – austinmarton

+0

Buena pregunta. Encontré [este enlace] (http://en.cppreference.com/w/cpp/language/auto) (vea Explicación/1) que sugiere que 'auto &&' puede funcionar como lvalue y rvalue dependiendo del inicializador. Adapto el ejemplo en consecuencia. – Pascal

Cuestiones relacionadas