J'ai testé la fonction de déplacement de c ++ 11, mais je ne suis pas devenue efficace. Qui peut me dire pourquoi? Merci. Le code est comme suit:

class Base {
  public:
   Base() { cout << "Base" << endl;}
   ~Base() { cout << "~Base" << endl;}

   Base(const Base& base) { cout << "Copy" << endl; }
   Base& operator=(const Base& base) {cout << "operator=" << endl;}

   Base(Base&& base) { cout << "move" << endl;}
   Base& operator=(Base&& base) { cout << "move=" << endl;}
};

Base b;

Base&& GetResult() {
  return std::move(b);
} 

int main() {
Base&& tmp = GetResult();

cout << &b << endl;
cout << &tmp << endl;

}

Production:

 Base
 0x6013a0
 0x6013a0
 ~Base

Pourquoi move copy et move operator= ne sont-ils pas appelés? Et pourquoi l'adresse est la même?

1
Pengcheng 20 avril 2017 à 18:23

3 réponses

Meilleure réponse

Pour ajouter aux excellentes réponses existantes, je crois que le principal point de confusion est ce que fait std::move.

std::move ne bouge pas.

Son nom était épouvantable .

Il ne vous donne qu'une valeur x faisant référence à tout ce que vous lui avez donné; cette xvalue se liera à une référence rvalue là où une lvalue ne le sera pas. Cela signifie que le résultat de std::move peut être donné à un constructeur de déplacement ou à un opérateur d'affectation de déplacement. Cependant, il ne fait pas cela pour vous, et vous ne le faites pas ici.


Compte tenu des critiques aussi vives pour la dénomination, vous avez sûrement une suggestion alternative
- user2079303

C'est un sujet très fréquenté, mais le créateur de C ++ suggère std::rval, et l'un des architectes du C ++ moderne suggère std::rvalue_cast (même si vous obtenez une valeur x ).

Personnellement, je pense que std::moveable aurait été un bon compromis.

7
Community 23 mai 2017 à 11:47

Pourquoi déplacer la copie et déplacer l'opérateur = ne pas être appelé?

Je suppose que par "déplacer la copie", vous voulez dire "déplacer le constructeur". L'opérateur d'affectation de déplacement n'est pas appelé, car vous n'utilisez jamais l'opérateur d'affectation.

Il n'y a pas de déplacements (ni de copies) car Base&& est une référence (une référence r-value pour être précis). Les références font référence / pointent vers un objet - elles ne contiennent pas l'état de l'objet. Lorsque vous initialisez une référence, aucun objet n'est copié ou déplacé.

Et pourquoi l'adresse est la même?

Lorsque l'opérateur address-of est appliqué à une référence, vous obtenez l'adresse de l'objet référencé.

3
eerorika 20 avril 2017 à 15:33

Ignorons la sémantique de déplacement pendant une minute et ne pensons qu'aux constructeurs de copie C ++ 98 familiers. Compte tenu du code suivant, quelle sortie attendez-vous?

class Base {
  public:
   Base() { cout << "Base" << endl;}
   ~Base() { cout << "~Base" << endl;}

   Base(const Base& base) { cout << "Copy" << endl; }
   Base& operator=(const Base& base) {cout << "operator=" << endl;}
};

Base b;

Base& GetResult() {
  return b;
} 

int main() {
  Base& tmp = GetResult();

  cout << &b << endl;
  cout << &tmp << endl;
}

Bien sûr, vous vous attendez à un appel au constructeur par défaut Base, suivi de l'adresse de b imprimée deux fois, suivi du destructeur Base. La raison en est que vous ne construisez qu'une seule instance Base et que vous ne la copiez jamais - vous n'utilisez que des références.

C'est donc avec votre exemple. Vous utilisez des références rvalue plutôt que des références lvalue, mais le point est le même - il n'y a qu'une seule variable Base, et aucune copie ou déplacement ne se produit . Si vous voulez voir la sémantique de déplacement en action, vous pouvez essayer quelque chose comme ceci:

Base getBase() {
    return Base{};
}

int main() {
    Base tmp = getBase();
    Base other = std::move(tmp);
}

(Le déplacement de getBase() sera probablement optimisé par le compilateur, mais vous devriez toujours voir le second.)

2
Tristan Brindle 20 avril 2017 à 15:37