Et voyons si cela change fortement la manière de passer ses paramètres en C++11. Imaginez que vous deviez implémenter une queue d'objets, par exemple pour la rendre thread safe. En c++03, l'on penserait immédiatement à écrire le "push" en passant son paramètre par référence constante, comme montré dans push1. Comparons donc cela avec push2, qui semble au premier abord moins optimal (notez que l'objet A affiche simplement quels sont ses constructeurs appelés):
class Queue { public: void push1(const A & a) { _deque.push_back(a); } void push2(A a) { _deque.push_back(std::move(a)); } private: std::deque<A> _deque; };
Voyons ce que cela donne dans le cas général:
Queue q; A a; q.push1(a);
affiche
A::A() A::A(const A &)
Alors que
Queue q; A a; q.push2(a);
affiche
A::A() A::A(const A &) A::A(const A &&)
C'est à peine pire si l'on part du principe qu'un constructeur move n'est pas cher. Mais maintenant, regardons dans le cas où le paramètre peut être déplacé:
Queue q; q.push1(A());
affiche
A::A() A::A(const A &)
ce qui n'est pas pire, mais
Queue q; q.push2(A());
affiche
A::A() A::A(const A &&)
et là, c'est nettement mieux! L'on évite complètement la copie, et l'on déplace simplement l'objet jusqu'à la queue. Notez que
Queue q; A a; q.push2(std::move(a));
affiche
A::A() A::A(const A &&) A::A(const A &&)
En effet, le standard autorise le compilo à transformer un passage par copie en un move.
Je suis un tout petit peu ennuyé par cette nouvelle approche. En effet, la règle jusqu'ici était, passe par référence si tu peux, et par autre chose si tu dois. Et maintenant, il va falloir choisir entre un passage par référence et un passage par copie en fonction de ce que la fonction va faire avec le paramètre, ce qui me donne l'impression de casser l'encapsulation. Mais économiser des copies est plaisant.
Aucun commentaire:
Enregistrer un commentaire