Que puis-je faire avec un objet déplacé?

138

La norme définit-elle précisément ce que je peux faire avec un objet une fois qu'il a été déplacé? J'avais l'habitude de penser que tout ce que vous pouvez faire avec un objet déplacé est de le détruire, mais cela ne serait pas suffisant.

Par exemple, prenez le modèle de swapfonction tel que défini dans la bibliothèque standard:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Évidemment, il doit être possible d'affecter des objets déplacés, sinon les lignes 2 et 3 échoueraient. Alors, que puis-je faire d'autre avec des objets déplacés? Où puis-je trouver exactement ces détails dans la norme?

(Au fait, pourquoi est-ce T c = std::move(a);au lieu de la T c(std::move(a));ligne 1?)

fredoverflow
la source

Réponses:

53

Les objets déplacés existent dans un état non spécifié, mais valide. Cela suggère que même si l'objet n'est peut-être plus capable de faire grand-chose, toutes ses fonctions membres devraient toujours présenter un comportement défini - y compris operator=- et tous ses membres dans un état défini - et il doit toujours être détruit. La norme ne donne aucune définition spécifique car elle serait unique à chaque UDT, mais vous pourrez peut-être trouver des spécifications pour les types standard. Certains comme les conteneurs sont relativement évidents - ils ne font que déplacer leur contenu et un conteneur vide est un état valide bien défini. Les primitives ne modifient pas l'objet déplacé.

Note latérale: je crois que c'est T c = std::move(a)ainsi que si le constructeur de déplacement (ou le constructeur de copie si aucun déplacement n'est fourni) est explicite, la fonction échouera.

Chiot
la source
26
Pas toutes ses fonctions membres exposeront le comportement défini. Seulement ceux sans conditions préalables. Par exemple, vous ne voulez probablement pas pop_backun fichier déplacé vector. Mais vous pouvez certainement savoir si c'est le cas empty().
Howard Hinnant
6
@Howard Hinnant: à pop_backpartir d'un vide vectora de toute façon un comportement indéfini, de mémoire, donc je suis à peu près sûr qu'à pop_backpartir d'un vecteur déplacé présentant un comportement non défini est cohérent.
Chiot
12
Nous discutons des objets déplacés. Pas d'objets connus pour être dans un état vide. Les objets déplacés ont un état non spécifié (sauf indication contraire bien entendu). [lib.types.movedfrom]
Howard Hinnant
5
@Howard Non spécifié, mais valide, donc pop_backse comporte toujours comme sur n'importe quel vecteur valide (peut-être même un vecteur vide).
Christian Rau
1
Que signifient non spécifié et valide dans ce contexte?
Ankur S
114

17.6.5.15 [lib.types.movedfrom]

Les objets des types définis dans la bibliothèque standard C ++ peuvent être déplacés de (12.8). Les opérations de déplacement peuvent être spécifiées explicitement ou générées implicitement. Sauf indication contraire, ces objets déplacés doivent être placés dans un état valide mais non spécifié.

Lorsqu'un objet est dans un état non spécifié, vous pouvez effectuer toute opération sur l'objet sans conditions préalables. Si vous souhaitez effectuer une opération avec des conditions préalables, vous ne pouvez pas effectuer directement cette opération car vous ne savez pas si l'état non spécifié de l'objet satisfait les conditions préalables.

Exemples d'opérations qui n'ont généralement pas de conditions préalables:

  • destruction
  • affectation
  • observateurs const tels que get, empty,size

Exemples d'opérations qui ont généralement des conditions préalables:

  • déréférencer
  • pop_back

Cette réponse apparaît désormais au format vidéo ici: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s

Howard Hinnant
la source
1
Mais je pourrais simplement vérifier les conditions préalables comme avec n'importe quel autre objet, non?
fredoverflow
6
@FredOverflow Tant que ces contrôles eux-mêmes n'ont pas de conditions préalables, bien sûr.
Christian Rau
1
@Chris: Mais en quoi est-ce différent d'un objet normal, non déplacé?
fredoverflow
2
Peut-être devrait être une question distincte, mais cela signifie-t-il: si j'ai une chaîne avec char* buffer;et int length;membres, mon constructeur / affectation de déplacement doit échanger (ou définir) la valeur des deux? Ou serait-ce OK, si la longueur n'était pas spécifiée (ce qui signifie que emptyet sizerenvoyer des valeurs sans signification)?
UncleBens du
3
@ 6502: Vous n'avez pas de sens. Une classe C ++ 03 ne «viole pas la norme C ++ 0x» car un cteur de déplacement s'il est généré violerait la norme. Et le code C ++ 03 ne déplacerait pas cette classe, il n'y a donc aucune raison pour qu'un moteur de déplacement soit généré.
MSalters