J'essaie de comprendre déplacer la sémantique et de copier / bouger élision.
Je voudrais une classe qui enveloppe certaines données. Je voudrais transmettre les données dans le constructeur et je voudrais posséder les données. P>
Après avoir lu Ceci , Ceci et Ce J'ai eu l'impression que, dans C ++ 11 si je veux stocker une copie, la valeur réussie doit être au moins aussi efficace que toute autre option (en dehors de la Problème mineure de la taille de code accrue). P>
Ensuite, si le code d'appel souhaiterait éviter une copie, elle peut en transmettre une r devalue au lieu d'une lvalue. (par exemple, utilisation STD :: Déplacer) P>
Alors je l'ai essayé: P>
1. DataWrapperWithMove: constructor move constructor 2. DataWrapperByValue: constructor move constructor move constructor 3. RVO: constructor move constructor
3 Réponses :
Je crois que c'est parce que vous faites essentiellement ce code.
std::cout << "2. DataWrapperByValue:\n"; Data d2; DataWrapperByValue a2(Data(std::move(d2))); // Notice a Data object is constructed.
Pour être plus explicite: le premier geste provient de d2 code> à
data code> et la seconde de
data code> à
data _ code>.
Votre exemple n'est pas précis, également DatawrapperbyValue code> ne prend pas de lvalue. Il déménage ou copie son argument en fonction de sa catégorie de valeur.
@Christrew, le constructeur de déplacement des données est appelé au lieu du constructeur de copie, il peut donc être correct.
@Christrew, pas de problème.
Votre conclusion à la référence pass-rvalue ainsi que la version par valeur pour les cas où vous obtenez une valeur L donne la meilleure performance. Cependant, cela est largement considéré comme optimisation prématurée. Howard Hinnant ( Meilleur moyen d'écrire un constructeur d'une classe qui contient un conteneur STL en C ++ 11 ) et Sean Parent ( http://channel9.msdn.com/events/ingnative/2013/Inhériittance-s-the-base-class-of-evil ) ont tous deux noté qu'ils considèrent cette optimisation prématurée. La raison en est que les mouvements sont censés être judicieux et pour les éviter dans ce cas provoqueraient une duplication de code, surtout si vous avez plus d'une argument qui peut être une valeur R ou L. Si, par profilement ou test, vous constatez que cet acuall dégradra la performance, vous pouvez toujours ajouter facilement la référence PASS-RVALUE après le fait. p> Un modèle utile dans un cas où vous avez besoin de performances supplémentaires est la suivante: p> ici Le constructeur fait toujours la bonne chose que possible dans Mon exemple en direct: http://ideone.com/usltra p> L'avantage de cette Le code argouruement complexe n'est probablement pas pertinent avec une seule argine, mais imaginez si votre constructeur avait 4 arguments pouvant être des valeurs R ou L, c'est bien mieux que d'écrire 16 constructeurs différents. P> DatawrapperbyValue :: Data _ code> est déplacé de
DatawrapperbyValue :: DatawrapperbyValue (DatawrapperbyValue (Data Data) Code> S Agler
DATA code> qui est déplacé de
D2 code>.
struct CompositeWrapperByMoveOrCopy {
Data data_;
Foo foo_;
Bar bar_;
Baz baz_;
template<typename T, typename U, typename V, typename W,
typename = typename std::enable_if<
std::is_same<typename std::decay<T>::type, Data>::value &&
std::is_same<typename std::decay<U>::type, Foo>::value &&
std::is_same<typename std::decay<V>::type, Bar>::value &&
std::is_same<typename std::decay<W>::type, Baz>::value
>::type
>
CompositeWrapperByMoveOrCopy(T&& data, U&& foo, V&& bar, W&& baz) :
data_{ std::forward<T>(data) },
foo_{ std::forward<U>(foo) },
bar_{ std::forward<V>(bar) },
baz_{ std::forward<W>(baz) } { }
};
DatawrapperbyValue code> a ce constructeur:
template<class U>
DataWrapperByValue(U&& u) : data_(std::forward<U>(u)) { }
Vous dites que la copie élision ne peut pas se produire ici. Est-il possible d'expliquer pourquoi la copie élision est possible dans le troisième cas lorsque la rvalue (une "privale") est créée à l'aide d'une valeur de retour mais pas dans le second cas lors de sa création à l'aide de STD :: Déplacer (un "XValue") ?
@Christrew Parce que le compilateur sait que l'objet étant renvoyé n'est plus nécessaire, il est donc dans ses droits d'élier le mouvement. Pour le second cas, il ne peut pas arriver car DatawrapperbyValue (données de données) code> n'est pas un constructeur de déplacement ni un constructeur de copie, il s'agit simplement d'un constructeur qui prend un objet code> de données code>. En tant que tel, la copie / mouvement ne peut pas être élue.
Ne pas utiliser Sfinae pour vérifier que le type correct peut entraîner des problèmes subtils. Imaginez si quelqu'un ajoute un constructeur explicite d'un Int à la classe de données, vous pouvez construire un DatawrapperbyValue à partir d'un int, ou même un float puisque vous ne saisissez pas data_
@Porkybrain mais bien sûr que ce n'est qu'un exemple. Je ne veux pas digresser en dehors du sujet immédiat.
Assez juste, dans l'exemple à la main, il n'est pas nécessaire.
Dupliquer possible de Meilleur moyen d'écrire un constructeur d'une classe qui détient un conteneur STL en C ++ 11