^Tous les temporaires non-nommés sont des rvalue, mais toutes les rvalue sont-elles des temporaires non-nommés?
@Koala01: Je vois qu'on est sur la même page.
^Tous les temporaires non-nommés sont des rvalue, mais toutes les rvalue sont-elles des temporaires non-nommés?
@Koala01: Je vois qu'on est sur la même page.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Si ce n'est qu'à ce moment là, ce n'est pas l'opérateur d'affectation "simple" qui sera utilisé, mais l'opérateur d'affectation par mouvement (celui qui prend, d'office, une rvalue référence : A(&& rhs) ).
Je ne vois donc pas en quoi cela pourrait changer quoi que ce soit au niveau de la manière de déclarer l'argument de l'opérateur simple.
L'une des solutions qui pourraient être envisagée, c'est, bien sur, de faire appel à l'opérateur d'affectation par mouvement dans le corps de l'opérateur d'affectation simple, mais, pour que cela marche, il faut que l'argument que l'on transmettra soit un objet temporaire non nommé, sous une forme proche de
A ce moment là, tu auras peut etre une élision de la copie au niveau de l'opérateur par mouvement, mais comme tu devras, de toutes manières, faire une copie implicite, autant passer rhs par référence constante pour s'éviter d'avoir, en plus, une copie supplémentaire au moment de l'appel de l'opérateur d'affectation si on vient à passer rhs par valeur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 A & operator=(A /* const & */ rhs){ *this.operator=(A(rhs)); return this; }
Bref, quoi qu'il en soit, l'argument de l'élision de copie ne représente pas un fondement technique sur lequel se baser pour décider s'il vaut mieux transmettre l'argument par valeur ou par référence constante à l'opérateur d'affectation normal
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Si tu n'as pas implémenté operator =(A&&) mais operator =(A), il faut que tu comprennes que même avec une rvalue
c'est bien operator=(A) qui sera appelé.
Si le compilateur supporte la copy ellision, la temporarie sera bindé directement dans le paramètre de l'operator =(A) autrement
le constructeur par mouvement de A sera utilisé, ce qui tu en conviendras ne représente pas non plus une copie
C'est au contraire encore une fois l'unique raison pour laquelle il est préférable d'utiliser l'arguement par valeurBref, quoi qu'il en soit, l'argument de l'élision de copie ne représente pas un fondement technique sur lequel se baser pour décider s'il vaut mieux transmettre l'argument par valeur ou par référence constante à l'opérateur d'affectation normal
la seule question qui reste à ce sujet est est-il préférable de fournir deux implémentations de operator = (pour les lvalue et pour les rvalue) où pour des raisons de simplifications se contenter de la forme operator =(A) (au prix d'un appel au constructeur de mouvement si appelé avec une rvalue)
A la base, une rvalue est "simplement" quelque chose qui peut se trouver à droit de l'opérateur =.
Donc : non toutes les rvalue ne sont pas des temporaires non nommés
Les choses deviennent intéressantes lorsque l'on s'intéressent aux rvalue references
Parce que, pour qu'il y ait rvalue reference, il faut qu'il y ait un objet temporaire.
Mais objet temporaire ne veux pas forcément dire non nommé:
La chaine (constante) "hello world" dans bar provoquera la création d'une std::string temporaire non nommée, ne pouvant donc être renvoyée que par valeur ou par rvalue reference.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 std::string && foo(/* params */) { std::string temp; /* ... */ return temp; } std::string && bar() { retrun "hello world"; }
Mais, a priori, temp est aussi un temporaire (dans le contexte de la fonction) dans le sens où la std::string sera détruite lorsque l'on sortira de la portée dans laquelle elle a été déclarée.
On ne pourrait donc pas renvoyer une référence dessus et la gérer, au niveau de la fonction appelante, sous une forme non constante (à moins de l'affecter à un objet bel et bien réel et non à une référence )
je crois en effet@Koala01: Je vois qu'on est sur la même page.
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
^Euh, il me semble que ces deux fonctions sont fausses (retour par référence d'une variable locale).
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Mais même un objet temporaire, fut il destiné à être détruit, doit être créé.
Un objet temporaire n'apparait pas "comme ca, par magie"!!! Et encore moins s'il doit présenter un état similaire à un autre objet existant!!!
C'est à dire qu'il y a d'office un constructeur qui est appelé !!!
Et le seul constructeur qui soit en mesure de s'assurer que l'objet créé présente un état similaire à un autre objet de même type, c'est le constructeur par copie.
Il sera donc appelé, que ce soit de manière implicite (dans le cas du passage par valeur) ou explicite (dans le cas du passage par référence constante), et cet appel au constructeur ne pourra pas être éludé.
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Hé bien, justement non...
C'est là tout l'attrait des rvalue reference
Je vous propose un peu de lecture au sujet des rvalue references et de la sémantique de mouvement (dont Returning an explicit rvalue-reference from a function pour ce qui concerne le retour d'une rvalue reference )
Le corps de la fonction est peut etre faux (j'aurais sans doute du appeler std::move), mais la signature de la fonction est correcte
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
http://stackoverflow.com/questions/1...more-efficient
"This returns a dangling reference, just like with the lvalue reference case. After the function returns, the temporary object will get destructed"
@koala01: Le seul exemple de retour de rvalue-reference dans le lien que tu m'as montré retourne une variable membre (ou globale) par référence, pas une variable locale.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Somme-nous d'accord, aussi, qu'une variable peut être un temporaire non-nommé dans un contexte et nommé dans un autre? Dans une telle fonction par exemple:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 A make_A(int val) { A temp(val); //Ici nommé temp.doSomething(); return A; //Ici possible NRVO } int main(void) { A a; foo(make_A()); //Ici temporaire non-nommé passé à foo(). }
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Mais si c'est le constructeur classique qui est appelé, il faut, déjà, récupérer la taille de manière explicite (est-ce taille() qu'il faut appeler, une autre fonction, accéder à un membre quelconque de la classe [EDIT] Et surtout: d'où vient elle [/EDIT]) et si tu arrives à faire en sorte que la taille soit indiquée de manière explicite, tu te retrouveras avec un array d'éléments, de la bonne taille, certes, mais dont les valeurs ne correspondent pas ([EDIT]ou du moins pas forcément[/EDIT]) aux valeurs de l'objet d'origine([EDIT]vu qu'elles correspondront aux valeurs éventuellement définies dans le constructeur[/EDIT]).
Or, le but de l'opérateur d'affectation est, justement, en sorte de faire que les valeurs de l'objet courent correspondent à celles de l'objet assigné, en faisant en sorte que le code
ne provoque aucune erreur!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 int main() { A a(10); A b(15); a[3]=15; b[3] = 20; b= a; assert(b.size() == 10); assert(b[3]==15); assert(b[3]==a[3]); }
Il t'est totalement impossible d'arriver à ce résultat si tu ne passe pas par le constructeur par copie!
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
^Normal, aucun des deux n'est une rvalue ni* un temporaire non-nommé.
Je n'ai pas bien compris lequel est nécessaire, mais vu qu'on n'a aucun des deux c'est bon.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
En extension de mon précédent exemple, voici un code qui montre bien l'élision de copie pour un retour de fonction chez moi:
Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <iostream> #include <algorithm> using namespace std; class A { int *ptr; public: void const *myAddr() const { return this; } A(int val) : ptr(new int) { *ptr = val; cout << myAddr() << ":ctor" << endl; } A(A const &src) : ptr(new int) { *ptr = *src.ptr; cout << myAddr() << ":copy" << endl; } ~A() { delete ptr; cout << myAddr() << ":dtor" << endl; } A& operator=(A tmp) { Swap(tmp); cout << myAddr() << ":opr=" << endl; return *this; } void Swap(A& obj) { swap(ptr, obj.ptr); } }; A make_A(int val) { A a(val); cout << "make_a: " << a.myAddr() << endl; return a; } int main(void) { A a(10); cout << "here it comes!" << endl; a = make_A(42); return 0; }
Code X : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 mingw32-g++.exe -O2 -Weffc++ -pedantic -std=c++98 -Wextra -Wall -c "C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.cpp" -o "C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.o" mingw32-g++.exe -o "C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.exe" "C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.o" Process terminated with status 0 (0 minutes, 0 seconds) 0 errors, 0 warnings Checking for existence: C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.exe Executing: C:\Program Files\CodeBlocks/cb_console_runner.exe "C:\Users\Frederic\Documents\VJ Codes CodeBlocks\CopyElision.exe" (in C:\Users\Frederic\Documents\VJ Codes CodeBlocks)(au passage, je suis choqué que l'affichage par défaut d'un void* ne force pas de taille minimale)
Code X : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 0x22ff0c:ctor here it comes! 0x22ff08:ctor make_a: 0x22ff08 0x22ff0c:opr= 0x22ff08:dtor 0x22ff0c:dtor Process returned 0 (0x0) execution time : 0.152 s Press any key to continue.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Cet exemple ne prouve malheureusement qu'une seule chose: le respect strict d'une règle aussi vieille que C++ : la durée de vie d'un objet renvoyé par valeur s'étend à celle de l'objet qui le récupère.
C'est effectivement une certaine forme d'élision de la copie, mais pas celle qui nous intéresse ici
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
moi je jette l'éponge , en espérant que quelqu'un de plus pédagogique parvienne à te mettre d'accord.
Euh, je ne vois pas quelle autre élision de copie existe.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Même si l'expresion std::move(a) est une rvalue, son évaluation ne créer pas d'objet temporaire, le c++11 à donc apporté une nouvelle notion: les xvalue.
on peut retenir le schéma ci-dessous :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 expressions / \ / \ / \ glvalues rvalues / \ / \ / \ / \ / \ / \ lvalues xvalues prvalues
Donc "mais toutes les rvalue sont-elles des temporaires non-nommés?", non seulement les prvalues (“pure” rvalue)
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager