44 votes

Donc, unique_ptr peut-il être utilisé en toute sécurité dans des collections stl?

Je suis confondu avec unique_ptr et rvalue déplacer la philosophie.

Disons que nous avons deux collections:

std::vector<std::auto_ptr<int>> autoCollection;
std::vector<std::unique_ptr<int>> uniqueCollection;

Maintenant, j'attendrais la suite à l'échec, car il est impossible de dire ce que l'algorithme est en train de faire à l'interne et peut-être faire de pivot interne des copies et autres, ainsi arrachant la propriété de l'auto_ptr:

std::sort(autoCollection.begin(), autoCollection.end());

Je reçois ce. Et le compilateur, à juste titre, n'autorise pas ce qui se passe.

Mais puis-je faire ceci:

std::sort(uniqueCollection.begin(), uniqueCollection.end());

Et cette compile. Et je ne comprends pas pourquoi. Je ne pense pas que unique_ptrs pourrait être copié. Est-ce à dire un pivot de la valeur ne peut être prise, si le tri est moins efficace? Ou est-ce pivot en fait un mouvement, qui, en fait, est aussi dangereux que la collection de auto_ptrs, et devrait être rejetée par le compilateur?

Je pense que je suis absent de certains élément crucial de l'information, donc j'attends avec impatience que quelqu'un me fournir de l'aha! moment.

53voto

Matthieu M. Points 101624

Je pense que c'est plus une question de philosophie que de la technique :)

La question sous-jacente est quelle est la différence entre les Déplacer et Copier. Je ne vais pas sauter dans technique / standardista de la langue, nous allons le faire simplement:

  • Copie: créer un autre objet identique (ou au moins, qu'il convient de comparer l'égalité)
  • Déplacer: prendre un objet et de le mettre dans un autre endroit

Comme vous l'avez dit, il est possible de mettre en œuvre Déplacer en terme de Copie: créer une copie dans le nouvel emplacement et jeter l'original. Il existe toutefois deux questions. L'un est de la performance, le deuxième est sur les objets utilisés pour le RAII: lequel des deux doit avoir la propriété ?

Un bon constructeur de Déplacement résout le 2 questions:

  • Il est clair quel est l'objet qui a la propriété: le nouveau, depuis l'origine sera rejeté
  • Il est donc inutile de copier les ressources souligné, ce qui permet une plus grande efficacité

L' auto_ptr et unique_ptr sont une très bonne illustration.

Avec un auto_ptr vous avez vissé Copie sémantique: l'original et la copie, ne compare pas l'égalité. Vous pouvez l'utiliser pour son Déplacement sémantique, mais il y a un risque que vous allez perdre de l'objet pointé quelque part.

D'autre part, l' unique_ptr , c'est exactement cela: il garantit l'unicité du propriétaire de la ressource, donc d'éviter la copie et l'inévitable problème de suppression qui va suivre. Et la pas de copie est garanti au moment de la compilation trop. Par conséquent, il est approprié dans des contenants tant que vous n'essayez pas d'avoir copie de l'initialisation.

typedef std::unique_ptr<int> unique_t;
typedef std::vector< unique_t > vector_t;

vector_t vec1;                           // fine
vector_t vec2(5, unique_t(new Foo));     // Error (Copy)
vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy)
vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end()));
    // Courtesy of sehe

std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator

std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy)

De sorte que vous pouvez utiliser unique_ptr dans un récipient (contrairement à auto_ptr), mais un certain nombre d'opérations sera impossible parce qu'ils impliquent la copie dont le type ne prend pas en charge.

Malheureusement Visual Studio peut être assez laxiste dans l'application de la norme et a également un certain nombre d'extensions que vous auriez besoin de les désactiver pour assurer la portabilité du code... de ne pas l'utiliser pour vérifier le niveau :)

13voto

rlbond Points 24215

Les unique_ptr s sont déplacés à l'aide de leur constructeur de déménagement. unique_ptr est Movable, mais pas CopyConstructable.

Il y a un excellent article sur les références rvalue ici . Si vous n'en avez pas encore entendu parler ou si vous êtes confus, jetez un coup d'oeil!

7voto

yonil Points 51

std::sort pourrait fonctionner uniquement avec les opérations de déplacement et aucune copie, aussi longtemps que il ya seulement une copie de chaque objet à un moment donné. C'est l'affaiblissement de l'exigence de travail en place, car en principe, on pourrait allouer un autre tableau temporairement et déplacer tous les objets, tandis que leur réorganisation.

par exemple, avec std::vector<std::unique_ptr<T>> supérieur à la capacité, il alloue de l'espace de stockage pour une plus grande vecteur, puis se déplace tous les objets de l'ancien stockage de la nouvelle. Ce n'est pas une opération mais il est parfaitement valide.

Comme il s'avère, algorithmes de tri comme le tri rapide et de tas de tri peut en effet travailler sur place sans difficulté. tri rapide de la partition de la routine utilise std::swap interne, qui compte comme une opération de déplacement pour les deux objets concernés. Lors de la sélection d'un pivot, une astuce consiste à échanger avec le premier élément de la gamme, de cette façon il ne sera jamais déplacé jusqu'à ce que le partitionnement est fini.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X