9
votes

Quand utiliser les constructeurs / missions de déplacement

J'ai cherché mais je ne trouve pas la réponse à "quand" pour les utiliser. Je continuais à entendre que c'est bien parce que cela me sauve une copie supplémentaire. Je suis allé le mettre dans chaque classe que j'avais mais de la façon dont cela ne semblait pas avoir de sens pour certaines classes: s J'ai lu d'innombrables tutoriels sur Lvalues ​​et Revalues ​​et STD :: Move vs STD :: Copie vs Memcpy vs. Memmove, etc. et même se lisez sur lancer () mais je ne suis pas sûr de continuer quand utiliser cela non plus.

Mon code ressemble à: P>

//Copy Con:
BMPS::BMPS(const BMPS& Bmp) : Bytes(((Bmp.width * Bmp.height) != 0) ? new RGB[Bmp.width * Bmp.height] : nullptr), width(Bmp.width), height(Bmp.height), size(Bmp.size), DC(0), Image(0)
{
    std::copy(Bmp.Bytes, Bmp.Bytes + (width * height), Bytes);
    BMInfo = Bmp.BMInfo;
    bFHeader = Bmp.bFHeader;
}

//Move Con:
BMPS::BMPS(BMPS&& Bmp) : Bytes(nullptr), width(Bmp.width), height(Bmp.height), size(Bmp.size), DC(0), Image(0)
{
    Bmp.Swap(*this);
    Bmp.Bytes = nullptr;
}

//Assignment:
BMPS& BMPS::operator = (BMPS Bmp)
{
    Bmp.Swap(*this);
    return *this;
}

//Not sure if I need Copy Assignment?

//Move Assignment:
BMPS& BMPS::operator = (BMPS&& Bmp)
{
    this->Swap(Bmp);
    return *this;
}

//Swap function (Member vs. Non-member?)
void BMPS::Swap(BMPS& Bmp) //throw()
{
    //I was told I should put using std::swap instead here.. for some ADL thing.
    //But I always learned that using is bad in headers.
    std::swap(Bytes, Bmp.Bytes);
    std::swap(BMInfo, Bmp.BMInfo);
    std::swap(width, Bmp.width);
    std::swap(height, Bmp.height);
    std::swap(size, Bmp.size);
    std::swap(bFHeader, Bmp.bFHeader);
}


0 commentaires

3 Réponses :


14
votes

Il y a une excellente pensée sur Blog de Scott Meyer < / a>:

Tout d'abord, toutes les demandes de copie ne peuvent pas être remplacées par des mouvements. Seules les demandes de copie pour les avales sont éligibles pour l'optimisation. Deuxièmement, tous les types ne soutiennent pas les opérations de déplacement plus efficaces que les opérations de copie. Un exemple est un std :: Array. Troisièmement, même des types qui soutiennent les opérations de déplacement efficaces ne peuvent supporter que peu de temps. Cas au point: STD :: String. Il prend en charge les mouvements, mais dans les cas où STD :: String est implémentée à l'aide de SSO (l'optimisation de la petite chaîne), de petites chaînes sont tout aussi coûteuses pour se déplacer quant à la copie!

Peut-être, vous pouvez catégoriser vos types en conséquence, puis décider quel besoin déplacer la sémantique. Remarque, qu'il existe des restrictions sur les opérateurs de ctors / ctors / mec de la génération automatique de compilateur, vous seriez donc bien conseillé de garder à l'esprit ceux-ci. Cela aide quand vous êtes explicitement spécifiant les membres de déplacement.

Pour les classes où vous ne spécifiez pas explicitement les membres du déplacement, il y a quelques points de la peine. Il y a aussi le problème de l'élément de déplacement explicitement / implicitement supprimé déplacement qui inhibe la copie de rvalues ​​. Une source de problèmes très précieuse de génération implicite de membres de déplacement peut être trouvée dans le papier de Stroustrup intitulé pour bouger ou ne pas bouger .

En ce qui concerne la manipulation des exceptions avec la sémantique de déplacement, je suggérerais Dave Abraham's Post Exceptionnellement en mouvement .

Je vais essayer de revenir à cette réponse avec quelques exemples lorsque je reçois le temps. Espérons que, pour le moment, les liens mentionnés ci-dessus vous aideront à démarrer.


1 commentaires

Cela m'a certainement commencé à commencer et à penser. Cela n'a pas répondu à certaines des questions que j'aurais aimé connaître des réponses spécifiques, mais elle est plus que suffisamment bonne pour que je commence à apprendre pour moi-même. Merci beaucoup.



3
votes

tandis que le mouvement est un très bon outil dans le sac qu'il permet beaucoup plus que la vitesse. Avec le déplacement, vous déplacez l'objet (évidemment) et ne laissez rien derrière (en dehors d'une carcasse vide, ou plus précisément un objet construit par défaut). Cela vous oblige alors à réfléchir plus attentivement à la propriété et à la conception du programme lorsque les objets de déplacement sont favorisés. Au lieu d'un accès multiple à certains objets ou partage, vous avancez clairement vous oblige à considérer qui a l'objet et quand.

Comme Bjarne Stroustrup a déclaré précédemment, nous devrions cesser de tout partager et avoir des pointeurs partout. Si vous utilisez des pointeurs, utilisez uniques_ptr et non partagée_ptr, sauf si vous souhaitez absolument partager la propriété (qui, dans de nombreux cas, vous ne le faites pas). Le constructeur unique_ptr et il ne bougent que le constructeur (copie bien supprimée) est un bon exemple d'un objet qui devrait fournir le déplacement et ne jamais copier.

Move est excellent et écrire des constructeurs de déplacement est une très bonne idée, encore mieux lorsque MSVC attire et permet aux décorateurs supprimés / défaillants sur les constructeurs générés par le compilateur (copie / assignation, etc.). Des erreurs comme une tentative d'accès à un membre précédemment supprimé sont très utiles ici, il suffit de faire des constructeurs privés une intention moins évidente d'un responsable du code. Dans les cas où la copie est correcte mais que vous déplacez préféré, un compilateur a choisi de se déplacer quand il peut (c'est-à-dire le test avec vector.push_back, qui sera avec certains compilateurs bouger ou gack_back si c'est raisonnable, achetant des gains de performance instantanés), donc dans Copier les objets du constructeur Un constructeur de déplacement défini peut automatiquement être sélectionné pour améliorer les performances (ignorant bien toutes les discussions SSO qui font rage en ce moment). C'est une réponse décente à Peruse

Il y a quelques fils assez lourds sur la liste de diffusion Boost d'avantage / inconvénient de la démarche / de la copie et de la transmission par valeur / référence qui parlent beaucoup de problèmes similaires, si vous recherchez des informations supplémentaires.


1 commentaires

J'ai définitivement apprécié ce lien et l'explication. Merci aussi! Le lien était très utile.



5
votes

Tout d'abord et avant tout: Utilisez la règle " de zéro " où que vous soyez. Voir " La règle de trois / cinq / zéro " et "<< a href = "https://github.com/isocpp/cppcoreguidelines/blob/master/cppcoreguidelines.md#rc-zero" rel = "noreferrer"> C-20 ".

Par conséquent: votre sentiment "bizarre" était correct: point et pa ne nécessite pas de copie et de déplacement explicites. Sinon, les réponses de Direntre et Dirvine et leurs références sont des lectures précises pour une compréhension plus détachée.

comme pour bmps C'est certainement une bonne idée de fournir des opérateurs de déplacement explicites.


1 commentaires

Merci pour votre réponse TERSE, très utile. La leçon facile à retenir à partir du premier WeLlink dit tout: "Les classes qui ont destructeurs personnalisées, copier / déplacer des constructeurs ou des opérateurs d'affectation de copie / déplacements doivent traiter exclusivement de la propriété"