web-dev-qa-db-fra.com

Itérer sur un conteneur de uniques_ptr

Comment accéder aux éléments unique_ptr d'un conteneur (via un itérateur) sans prendre possession du conteneur? Quand on obtient un itérateur vers un élément dans le conteneur, la propriété de l'élément est-elle toujours avec le conteneur? Et quand on déréférence l'itérateur pour accéder à unique_ptr? Cela effectue-t-il un déplacement implicite de unique_ptr?

Je trouve que j'utilise beaucoup shared_ptr lorsque j'ai besoin de stocker des éléments dans un conteneur (pas par valeur), même si le conteneur possède conceptuellement les éléments et que d'autres codes souhaitent simplement manipuler des éléments dans le conteneur, car j'ai peur de ne pas pouvoir accéder réellement aux éléments unique_ptr dans le conteneur sans que la propriété ne lui en soit retirée.

Des idées?

31
Dr DR

Tant que vous n'essayez pas de faire une copie du unique_ptr, vous pouvez simplement l'utiliser. Vous devrez "double déréférencer" l'itérateur pour obtenir la valeur du pointeur, comme vous le feriez avec shared_ptr. Voici un bref exemple:

#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 vous faites (accidentellement) une copie de unique_ptr:

Ptr p = v[0];

alors vous le découvrirez au moment de la compilation. Cela ne provoquera pas d'erreur d'exécution. Votre cas d'utilisation est la raison pour laquelle container<unique_ptr<T>> a été construit. Les choses devraient juste fonctionner, et si ce n'est pas le cas, le problème apparaît au moment de la compilation au lieu de l'exécution. Donc, code loin, et si vous ne comprenez pas l'erreur de compilation, posez une autre question ici.

16
Howard Hinnant

Avec auto et les boucles for basées sur les plages de C++ 11, cela devient relativement élégant:

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

Le référence & à la std::unique_ptr évite la copie et vous pouvez utiliser le uniqe_ptr sans déréférencement.

47
Pascal