C++11 constructeur de déplacement
Quelle serait la bonne façon d'implémenter un constructeur de mouvements en considérant la classe suivante:
class C {
public:
C();
C(C&& c);
private:
std::string string;
}
bien sûr, l'idée est d'éviter de copier string
ou le désallouer deux fois.
Supposons l'exemple de base est juste pour la clarté et la j'ai besoin d'un constructeur de déplacement.
j'ai essayé:
C::C(C&& c) {
//move ctor
string = std::move(c.string);
}
Et
C::C(C&& c) : string(std::move(c.string)) {
//move ctor
}
compilez fine sur gcc 4.8 et exécutez fine. semble l'option A est le comportement correct,string
est copié au lieu d'être déplacé avec l'option B.
Est-ce l'implémentation correcte d'un constructeur de déménagement?
4 réponses
Depuis std::string
lui-même a un move-ctor, le move-ctor implicitement défini pour C
s'occupera de l'opération de déménagement. Vous ne pouvez pas le définir vous-même. Cependant, si vous avez un autre membre de données et spécifiquement:
12.8 copier et déplacer des objets de classe
12 un constructeur de copie/déplacement implicitement déclaré est un public en ligne membre de sa catégorie. Un constructeur de copie /déplacement pour une classe X être défini comme supprimé (8.4.3) si X a:
- une variante avec un membre non-trivial correspondant constructeur et X est une union-comme la classe,
- un données non statiques membre de la classe de type M (ou de son réseau) qui ne peut pas être copié / déplacé en raison de la résolution de surcharge (13.3), tel qu'il est appliqué aux M le constructeur correspondant, résulte en une ambiguïté ou une fonction qui est supprimé ou inaccessible du constructeur défaillant, ou
- un direct ou classe de base virtuelle B qui ne peut pas être copiée/déplacée parce que résolution de surcharge (13.3), appliquée aux valeurs correspondantes de B constructeur, les résultats dans une ambiguïté ou une fonction qui est supprimé ou inaccessible du constructeur défaillant, ou
- pour le déplacer constructeur, membre de données non statique ou classe de base directe ou virtuelle avec un type qui n'a pas un constructeur de déplacement et n'est pas trivialement copiable.
13 Un copier/déplacer le constructeur pour la classe X est trivial s'il est ni l'utilisateur, ni supprimé, si
- la classe X n'a pas de fonctions virtuelles (10.3) et pas de classes de base virtuelles (10.1), et fonctions (10.3) et pas de classes de base virtuelles (10.1), et
- constructeur sélectionné pour copier/déplacer chaque classe de base directe sous-objet est trivial, et
- pour chaque membre de données non statiques de X qui est de la classe type (ou tableau), le constructeur sélectionné pour copier/déplacer que le membre est trivial, sinon le constructeur de copie/mouvement est non trivial.
vous pouvez implémenter votre propre mouvement-ctor.
dans le cas où vous avez besoin du move-ctor, préférez la syntaxe de la liste initialiseur. Toujours! Sinon, vous pouvez finir avec une construction par défaut par objet non mentionné dans la liste initialiseur (ce qui est ce que vous êtes forcé pour les objets membres avec des cteurs non par défaut seulement).
vos deux variantes vont déplacer la chaîne. La seconde variante devrait être préférée parce qu'elle ne construira pas par défaut une chaîne vide juste pour la déplacer ensuite.
Vérifiez votre testcase puis la liste des bugzilla de votre compilateur. Vous devez tracer les appels aux deux string::operator=(string&&)
(1er cas) etstring::string(string&&)
(2e cas) si vous voulez vous assurer pour les deux cas qu'ils se déplacent.
les deux constructeurs devraient fonctionner. Donc les deux sont des constructeurs de mouvements corrects. La seconde pourrait être plus efficace, puisque le premier défaut des constructions string
seulement pour lui assigner, alors que le second se contentera de déplacer le construire et devrait donc être plus efficace. Si le second est moins efficace, je suspecterais un bug de compilateur (rappelez-vous que le support C++11 n'est toujours pas complet pour les compilateurs actuels) ou une méthodologie de test défectueuse (comment exactement faites-vous pour tester la copie vs déplacer et Êtes-vous sûr dans les deux cas, le nom du constructeur du mouvement n'est pas celui de l'op d'affectation?).
bien sûr chaque fois que possible vous pouvez simplement laisser le compilateur générer votre constructeur via C(C&&) = default;
.
il n'y a pas besoin d'implémenter un constructeur move ici puisque vous n'avez pas besoin de gérer manuellement la mémoire. Les constructeurs de déplacement ne sont utiles que lorsque vous utilisez manuellement des tableaux dynamiques dans votre classe.
Vous pouvez toujours demander explicitement au compilateur de créer le constructeur de mouvements par défaut même s'il aurait déjà dû être fait même si vous ne le demandez pas:
C(C&& c) = default;