29 votes

Pourquoi est-ce que C++ vous permettent de déplacer des classes contenant des objets supprimés opérations de déplacement?

Pourquoi suis-je autorisé à utiliser std::move sur une classe qui contient des champs d'un type avec supprimés sémantique de déplacement (cas 1), mais je ne suis pas autorisé à l'utiliser sur une instance d'une telle classe (cas 2)?

Je comprends le cas 2. J'ai explicitement supprimé le constructeur de déplacement, donc, je reçois un message d'erreur si j'essaie de la déplacer. Mais je m'attends à ce que ce serait aussi le cas dans le cas 1, où cette catégorie est également déplacé.

class TestNonMovable {
  std::string ss;
 public:
  TestNonMovable(){}
  TestNonMovable(const TestNonMovable&) {}
  TestNonMovable(TestNonMovable&&) = delete;
};

class SomeClass {
  TestNonMovable tnm;
};

int main() {    
    // case1: This compiles, my understanding is that for SomeClass::tnm compiler will use copy constrctor
    SomeClass sc1;
    SomeClass sc2 = std::move(sc1);

    // case2: This does not compile, move constructor is explicitly deleted, compiler will not try using copy constructor
    TestNonMovable tnm;
    TestNonMovable tnm2 = std::move(tnm); //error: use of deleted function 'TestNonMovable::TestNonMovable(TestNonMovable&&)'
}

45voto

songyuanyao Points 2265

Notez la différence entre les deux classes. Pour TestNonMovable (cas 2), vous explicitement déclarer le constructeur de déplacement en tant que delete. Avec TestNonMovable tnm2 = std::move(tnm); supprimés constructeur de déplacement est sélectionné dans la résolution de surcharge et puis la cause de l'erreur.

Pour SomeClass (cas 1), vous n'avez pas à déclarer explicitement le déplacer et le constructeur de copie. Le constructeur de copie sera implicitement déclarée et définie, mais le constructeur de déplacement sera implicitement déclarée et définie comme étant supprimé, car il a une non-mobiles membre de données. Remarque l' supprimé déclarée implicitement constructeur de déplacement ne participeront pas à la résolution de surcharge. Avec SomeClass sc2 = std::move(sc1);, le constructeur de copie est sélectionné et que le code fonctionne très bien. La référence rvalue retourné à partir de std::move pourrait être lié à la lvalue-référence const (c - const SomeClass&) trop.

L'supprimé implicitement déclarées constructeur de déplacement est ignoré par la résolution de surcharge (sinon il serait d'empêcher la copie de l'initialisation de rvalue). (depuis C++14)

BTW: std::move en lui-même est autorisé dans les deux cas. Il n'a pas d'effectuer l' opération de déplacement, c'est juste convertit l'argument de rvalue. L'opération de déplacement arrive au moment de la construction dans les deux cas.

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