Question

Si j'ai une classe telle que

class Foo{
public:
    Foo(){...}
    Foo(Foo && rhs){...}
    operator=(Foo rhs){ swap(*this, rhs);}
    void swap(Foo &rhs);
private:
    Foo(const Foo&);
// snip: swap code
};
void swap(Foo& lhs, Foo& rhs);

Est-il judicieux de mettre en œuvre l'opérateur = en valeur et échange si je n'ai pas un constructeur de copie? Il doit éviter de copier mes objets de la classe Foo mais permettent mouvements.

Cette classe n'est pas copiable, donc je ne devrais pas être en mesure de copier ou de copier construction de lui attribuer.

Modifier

Je l'ai testé mon code avec cela et il semble avoir le comportement que je veux.

#include <utility>
#include <cstdlib>
using std::swap;
using std::move;
class Foo{
public: Foo():a(rand()),b(rand()) {}
        Foo(Foo && rhs):a(rhs.a), b(rhs.b){rhs.a=rhs.b=-1;}
        Foo& operator=(Foo rhs){swap(*this,rhs);return *this;}
        friend void swap(Foo& lhs, Foo& rhs){swap(lhs.a,rhs.a);swap(lhs.b,rhs.b);}
private:
    //My compiler doesn't yet implement deleted constructor
    Foo(const Foo&);
private:
    int a, b;
};

Foo make_foo()
{
    //This is potentially much more complicated
    return Foo();
}

int main(int, char*[])
{
    Foo f1;
    Foo f2 = make_foo(); //move-construct
    f1 = make_foo(); //move-assign
    f2 = move(f1);
    Foo f3(move(f2));
    f2 = f3; // fails, can't copy-assign, this is wanted
    Foo f4(f3); // fails can't copy-construct

    return 0;
}
Était-ce utile?

La solution

Déplacer et-swap est en effet raisonnable. Si vous désactivez le constructeur de copie, la seule façon que vous pouvez invoquer cette fonction est que si vous deviez construire l'argument avec le constructeur de déplacement. Cela signifie que si vous écrivez

lhs = rhs; // Assume rhs is an rvalue

Ensuite, le constructeur de l'argument à operator = sera initialisé avec le constructeur de déplacement, vidant rhs et définissant l'argument à l'ancienne valeur de rhs. L'appel à swap puis ancienne valeur des échanges de lhs et ancienne valeur de rhs, laissant ancienne valeur de lhs tenue rhs. Enfin, le destructor pour les feux argument, nettoyage lhs est vieux souvenir. Comme une note, ce qui est vraiment pas copier -et-échange autant que move -et-échange.

Cela dit, ce que vous avez maintenant est incorrect. L'implémentation par défaut de std::swap essayera interne d'utiliser le constructeur de déplacement pour déplacer les éléments autour, qui se traduit par une boucle de récursion infinie. Il faudrait surcharge std::swap pour obtenir ce bien au travail.

Vous pouvez voir cette ligne ici à ideone.

Pour plus d'informations, consultez cette question et la discussion sur la « règle de quatre et demi. »

Hope this helps!

Autres conseils

Je pense que cela est bien beau, mais je ne comprends pas vraiment pourquoi vous pas seulement faire:

operator=(Foo&& rhs) // pass by rvalue reference not value

Et Epargnez-vous déplacer.

Ce qui suit est l'opinion, et je ne suis pas vraiment sur la norme 0x, mais je pense avoir un raisonnement assez solide me sauvegarde.

Non

. En fait, il serait bon de ne pas l'affectation de soutien à tous.

Considérez la sémantique:

« Assigner » signifie « cause B, qui existe déjà, soit identique à A ». « Copie » signifie « créer B, et l'amener à être identique à A ». « Swap » signifie « la cause B soit identique à ce que A était, et en même temps la cause A à être identique à ce que B était ». "Move" signifie "la cause B soit identique à ce que A était, et détruire un."

Si nous ne pouvons pas copier, alors nous ne pouvons pas copier-échange. Copier-échange est censé être un moyen sûr de mettre en œuvre la cession: nous créons C qui est identique à A, échanger avec B (de sorte que C est maintenant ce que B était, et B est identique à A) et détruisons C (nettoyer les anciennes données B). Cela ne fonctionne tout simplement pas avec mouvement et-échange: nous ne devons pas détruire A à tout moment, mais le mouvement va le détruire. En outre, le déplacement ne crée pas une nouvelle valeur, donc ce qui se passe est que nous passons A dans B, et il n'y a rien à échanger avec.

D'ailleurs - la raison de faire la noncopyable de classe est sûrement pas parce que « créer B » sera problématique, mais parce que « l'amener à être identique à A » sera problématique. OIEau, si nous ne pouvons pas copier, pourquoi devrions-nous attendre à être en mesure d'attribuer?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top