PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > fr.comp.lang.c++ > C++0X : Rvalue references
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
C++0X : Rvalue references

Réponse
 
LinkBack Outils de la discussion
Vieux 20/03/2008, 09h17   #1
Mickaël Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut C++0X : Rvalue references

Bonjour la liste,

Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.

À quoi cela correspond-t-il concrètement ? Quelle en est l'utilité
pratique ?

<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html>

Merci pour vos éclaircissements.
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
  Réponse avec citation
Vieux 20/03/2008, 09h55   #2
Michael DOUBEZ
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Mickaël Wolff a écrit :
> Bonjour la liste,
>
> Je n'arrive pas à saisir le concept des « rvalue references », promis
> pour la prochaine normalisation du C++.
>
> À quoi cela correspond-t-il concrètement ? Quelle en est l'utilité
> pratique ?
>
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html>
>
> Merci pour vos éclaircissements.


Pour moi, les principaux apports sont :

1. la sémantique de déplacement (move semantic).

C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.

C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.

C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partagée
(comptage de référence).

2. Utilisation de temporaires en tant que paramètre non const.

Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.

logstream get_log_stream();

Aujourdhui, tu ne peux pas faire:

get_log_stream()<<"LOG: Error "<<errno<<std::endl;

Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}

Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.

Avec les reférences Rvalues:
template<typename T>
ostream& operator<<(ostream&& os, const T& t)
{
// ...
return std::forward<ostream>(os);
}

Tu peux ensuite faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
// destruction de la temporaire renvoyée par get_log_stream()
// et utiliser RAII pour faire ce que tu veux.


Michael
  Réponse avec citation
Vieux 20/03/2008, 10h34   #3
Michel Decima
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Michael DOUBEZ a écrit :
> Mickaël Wolff a écrit :
>> Bonjour la liste,
>>
>> Je n'arrive pas à saisir le concept des « rvalue references », promis
>> pour la prochaine normalisation du C++.


> 2. Utilisation de temporaires en tant que paramètre non const.
>
> Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
> une fonction en tant que paramètre non-const (Pour peu que la class soit
> moveable).Une application pratique est une fonction get_log_stream() qui
> te renvoie une stream que tu vas utiliser pour contruire un log; le log
> est envoyé à la destruction de la stream.
>
> logstream get_log_stream();
>
> Aujourdhui, tu ne peux pas faire:
>
> get_log_stream()<<"LOG: Error "<<errno<<std::endl;


En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :

template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std:stream* target = dest.getStream() ) {
*target << src;
}
return dest;
}

Au passage: merci James.

Mais c'est vrai qu'avec le move, c'est beaucoup plus simple, puisque
tout le bazar necessaire jusqu'a present sera offert par le langage.
  Réponse avec citation
Vieux 20/03/2008, 19h59   #4
zais ethael
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

On 20 mar, 10:34, Michel Decima <michel.dec...@orange-ft.com> wrote:
> Michael DOUBEZ a écrit :
>
>
>
> > Mickaël Wolff a écrit :
> >> Bonjour la liste,

>
> >> Je n'arrive pas à saisir le concept des « rvalue references », promis
> >> pour la prochaine normalisation du C++.

> > 2. Utilisation de temporaires en tant que paramètre non const.

>
> > Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
> > une fonction en tant que paramètre non-const (Pour peu que la class soit
> > moveable).Une application pratique est une fonction get_log_stream() qui
> > te renvoie une stream que tu vas utiliser pour contruire un log; le log
> > est envoyé à la destruction de la stream.

>
> > logstream get_log_stream();

>
> > Aujourdhui, tu ne peux pas faire:

>
> > get_log_stream()<<"LOG: Error "<<errno<<std::endl;

>
> En fait si, tu peux le faire, a condition que get_log_stream renvoie
> un proxy copiable, avec un comptage de reference et un operator<<
> template qui prend en premier argument un const :
>
> template< typename T >
> inline OutputStreamWrapper const&
> operator<<( OutputStreamWrapper const& dest, T const& src )
> {
> if ( std:stream* target = dest.getStream() ) {
> *target << src;
> }
> return dest;
>
> }
>
> Au passage: merci James.
>
> Mais c'est vrai qu'avec le move, c'est beaucoup plus simple, puisque
> tout le bazar necessaire jusqu'a present sera offert par le langage.


Une remarque pour dire qu'il y a une petite subtilité. J'ai déjà du le
faire et ça ne fonctionnait pas parfaitement, bizarrement les
manipulateurs passaient mal. Il faut aussi rajouter 2 ou 3 méthodes
définies dans std::iostream (ou une classe de base) en plus d'un
opérateur << généraliste (ça fait un bout de temps, je ne me souviens
plus lesquelles ni comment j'avais déduit qu'il fallait les définir,
mais je me souviens que j'avais bien galèré).
  Réponse avec citation
Vieux 20/03/2008, 22h00   #5
Michel Decima
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

zais ethael a écrit :
> On 20 mar, 10:34, Michel Decima <michel.dec...@orange-ft.com> wrote:


>> En fait si, tu peux le faire, a condition que get_log_stream renvoie
>> un proxy copiable, avec un comptage de reference et un operator<<
>> template qui prend en premier argument un const :
>>
>> template< typename T >
>> inline OutputStreamWrapper const&
>> operator<<( OutputStreamWrapper const& dest, T const& src )
>> {
>> if ( std:stream* target = dest.getStream() ) {
>> *target << src;
>> }
>> return dest;
>>
>> }


> Une remarque pour dire qu'il y a une petite subtilité. J'ai déjà du le
> faire et ça ne fonctionnait pas parfaitement, bizarrement les
> manipulateurs passaient mal. Il faut aussi rajouter 2 ou 3 méthodes
> définies dans std::iostream (ou une classe de base) en plus d'un
> opérateur << généraliste (ça fait un bout de temps, je ne me souviens
> plus lesquelles ni comment j'avais déduit qu'il fallait les définir,
> mais je me souviens que j'avais bien galèré).


Effectivement, ca ne suffit pas, je n'avais pas tout dit. Pour les
manipulateurs sous forme de pointeurs de fonctions (ie ceux qui ne sont
pas dans <iomanip>) il faudra ajouter deux operateurs :

inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ios_base& ( *src )( std::ios_base& ) )
{
if ( std:stream* target = dest.getStream() ) {
*target << src;
}
return dest;
}

inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std:stream& ( *src )( std:stream& ) )
{
if ( std:stream* target = dest.getStream() ) {
*target << src;
}
return dest;
}

je viens de refaire le test, et j'ai bien l'impression que le premier
est inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.


  Réponse avec citation
Vieux 21/03/2008, 08h37   #6
Jean-Marc Bourguet
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Michel Decima <michel.decima@wanadoo.fr> writes:

> je viens de refaire le test, et j'ai bien l'impression que le premier est
> inutile (std::hex peut passer par la version generique) alors que
> le second est necessaire pour std::endl... bizarre.


std::hex n'est pas template, std::endl l'est. Ce doit etre une histoire de
deductibilite de parametres templates.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/...ite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
  Réponse avec citation
Vieux 21/03/2008, 09h07   #7
Michel Decima
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Jean-Marc Bourguet a écrit :
> Michel Decima <michel.decima@wanadoo.fr> writes:
>
>> je viens de refaire le test, et j'ai bien l'impression que le premier est
>> inutile (std::hex peut passer par la version generique) alors que
>> le second est necessaire pour std::endl... bizarre.

>
> std::hex n'est pas template, std::endl l'est. Ce doit etre une histoire de
> deductibilite de parametres templates.


Tres bonne remarque. Dans mon code je ne me sert que de std:stream,
donc j'ai fini par "oublier" son coté template, qui reapparait forcement
du coté de certains manipulateurs... merci pour le rappel.

  Réponse avec citation
Vieux 21/03/2008, 09h53   #8
Etienne
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Bonjour,

> 1. la sémantique de déplacement (move semantic).
>
> C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
> l'ancien, tu peux directement transférer l'objet à un autre endroit de
> la mémoire.
>
> C'est intéressant pour les swap par example où tu n'est plus obligé
> d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
> juste un move comme tu le ferais avec un memcpy pour des POD.
>
> C'est aussi intéressant pour les ressources qui ne doivent pas être
> dupliquées comme les mutex. C'est en fait une autre application de swap
> (sans spécialisation requise). Ou encore pour faire la distinction entre
> une copy où la ressource doit être dupliquée ou peut rester partagée
> (comptage de référence).


pas de problème pour comprendre que vaut la source :

struct Pouet {... };

Pouet p1;
..
..
.
Pouet && p2 = p1; //
// Quelle valeur prend p1 ?


> 2. Utilisation de temporaires en tant que paramètre non const.
>
> Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
> une fonction en tant que paramètre non-const (Pour peu que la class soit
> moveable).Une application pratique est une fonction get_log_stream() qui
> te renvoie une stream que tu vas utiliser pour contruire un log; le log
> est envoyé à la destruction de la stream.
>
> logstream get_log_stream();
>
> Aujourdhui, tu ne peux pas faire:
>
> get_log_stream()<<"LOG: Error "<<errno<<std::endl;
>
> Parce que les fonctions de stream sont de la forme:
> template<typename T>
> ostream& operator<<(ostream& os, const T& t)
> {
> // ...
> return os;
>
> }
>
> Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
> n'est pas const.


Je ne comprends pas trop pk cela ne compile pas :

class Pouet
{
public:
Pouet(void)
{
std::cout << "Pouet(void) this=" << this << std::endl;
}

~Pouet(void)
{
std::cout << "~Pouet(void) this=" << this << std::endl;
}

template <class T> Pouet& print(const T&t)
{
std::cout << "print(const T&t) t=" << t << std::endl;
return *this;
}
};

template<class T>
Pouet & operator<<(Pouet & p, const T & t)
{
p.print(t);
return p;
}

Pouet get_truc(void)
{
Pouet p;
return p;
}

//
// La ligne suivant ne compile pas oki
get_truc() << "Bllla bllaaa" << 5 << " truc";

//
// Par contre la ligne suivant compile
get_truc().print("Bllla bllaaa").print(5).print("truc");

Pourquoi la seconde ligne compile ?

Etienne
  Réponse avec citation
Vieux 22/03/2008, 10h23   #9
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

On 20 mar, 22:00, Michel Decima <michel.dec...@wanadoo.fr> wrote:
> zais ethael a écrit :
> > On 20 mar, 10:34, Michel Decima <michel.dec...@orange-ft.com> wrote:
> >> En fait si, tu peux le faire, a condition que
> >> get_log_stream renvoie un proxy copiable, avec un comptage
> >> de reference et un operator<< template qui prend en premier
> >> argument un const :


> >> template< typename T >
> >> inline OutputStreamWrapper const&
> >> operator<<( OutputStreamWrapper const& dest, T const& src )
> >> {
> >> if ( std:stream* target = dest.getStream() ) {
> >> *target << src;
> >> }
> >> return dest;
> >> }


> > Une remarque pour dire qu'il y a une petite subtilité. J'ai
> > déjà du le faire et ça ne fonctionnait pas parfaitement,
> > bizarrement les manipulateurs passaient mal. Il faut aussi
> > rajouter 2 ou 3 méthodes définies dans std::iostream (ou une
> > classe de base) en plus d'un opérateur << généraliste (ça
> > fait un bout de temps, je ne me souviens plus lesquelles ni
> > comment j'avais déduit qu'il fallait les définir, mais je me
> > souviens que j'avais bien galèré).


> Effectivement, ca ne suffit pas, je n'avais pas tout dit. Pour
> les manipulateurs sous forme de pointeurs de fonctions (ie
> ceux qui ne sont pas dans <iomanip>) il faudra ajouter deux
> operateurs :


> inline OutputStreamWrapper const&
> operator<<( OutputStreamWrapper const& dest,
> std::ios_base& ( *src )( std::ios_base& ) )
> {
> if ( std:stream* target = dest.getStream() ) {
> *target << src;
> }
> return dest;
> }


> inline OutputStreamWrapper const&
> operator<<( OutputStreamWrapper const& dest,
> std:stream& ( *src )( std:stream& ) )
> {
> if ( std:stream* target = dest.getStream() ) {
> *target << src;
> }
> return dest;
> }


> je viens de refaire le test, et j'ai bien l'impression que le
> premier est inutile (std::hex peut passer par la version
> generique) alors que le second est necessaire pour
> std::endl... bizarre.


En effet. Comme a dit Jean-Marc, std::hex n'est pas un
template, donc, pas de problème avec la version générique.

En fait, j'ai rencontré le problème avec std::endl, qui lui
prend comme paramètre un std::basic_ostream<> (et donc, est un
template). Sachant qu'il y a aussi beaucoup de manipulateurs
bi-directionnels, j'ai ajouté en même temps une spécialisation
pour eux. Sans trop y reflechir sur le fait que std::ios_base
n'est pas un template. Et évidemment, puisque le code passait
tous les tests par la suite, je ne me suis plus posé de
question.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

  Réponse avec citation
Vieux 25/03/2008, 13h17   #10
Michael DOUBEZ
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Etienne a écrit :
> Bonjour,
>
>> 1. la sémantique de déplacement (move semantic).
>>
>> C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
>> l'ancien, tu peux directement transférer l'objet à un autre endroit de
>> la mémoire.
>>
>> C'est intéressant pour les swap par example où tu n'est plus obligé
>> d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
>> juste un move comme tu le ferais avec un memcpy pour des POD.
>>
>> C'est aussi intéressant pour les ressources qui ne doivent pas être
>> dupliquées comme les mutex. C'est en fait une autre application de swap
>> (sans spécialisation requise). Ou encore pour faire la distinction entre
>> une copy où la ressource doit être dupliquée ou peut rester partagée
>> (comptage de référence).

>
> pas de problème pour comprendre que vaut la source :
>
> struct Pouet {... };
>
> Pouet p1;
> ..
> ..
> .
> Pouet && p2 = p1; //
> // Quelle valeur prend p1 ?
>
>
>> 2. Utilisation de temporaires en tant que paramètre non const.
>>
>> Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
>> une fonction en tant que paramètre non-const (Pour peu que la class soit
>> moveable).Une application pratique est une fonction get_log_stream() qui
>> te renvoie une stream que tu vas utiliser pour contruire un log; le log
>> est envoyé à la destruction de la stream.
>>
>> logstream get_log_stream();
>>
>> Aujourdhui, tu ne peux pas faire:
>>
>> get_log_stream()<<"LOG: Error "<<errno<<std::endl;
>>
>> Parce que les fonctions de stream sont de la forme:
>> template<typename T>
>> ostream& operator<<(ostream& os, const T& t)
>> {
>> // ...
>> return os;
>>
>> }
>>
>> Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
>> n'est pas const.

>
> Je ne comprends pas trop pk cela ne compile pas :
>
> class Pouet
> {
> public:
> Pouet(void)
> {
> std::cout << "Pouet(void) this=" << this << std::endl;
> }
>
> ~Pouet(void)
> {
> std::cout << "~Pouet(void) this=" << this << std::endl;
> }
>
> template <class T> Pouet& print(const T&t)
> {
> std::cout << "print(const T&t) t=" << t << std::endl;
> return *this;
> }
> };
>
> template<class T>
> Pouet & operator<<(Pouet & p, const T & t)
> {
> p.print(t);
> return p;
> }
>
> Pouet get_truc(void)
> {
> Pouet p;
> return p;
> }
>
> //
> // La ligne suivant ne compile pas oki
> get_truc() << "Bllla bllaaa" << 5 << " truc";
>
> //
> // Par contre la ligne suivant compile
> get_truc().print("Bllla bllaaa").print(5).print("truc");
>
> Pourquoi la seconde ligne compile ?


La différence entre les deux lignes est que:
1. Dans la premières, tu invoques:
Pouet & operator<<(Pouet & p, const T & t);
mais que la variable locale revoyée par la fonction get_truc() ne peux
pas être liée à une référence, donc ça ne compile pas.

2. Dans là deuxième ligne, tu invoques l'équivalent de:
Pouet& Pouet::print<T>(Pouet* this, const T& t);
La variable locale peut être liée à un pointeur donc pas de problème.

D'ailleur, la ligne suivante devrait compiler:
get_truc().print("Bllla bllaaa")<<"5"<<"truc";

Michael
  Réponse avec citation
Vieux 26/03/2008, 09h33   #11
Mickaël Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Michael DOUBEZ a écrit :
> Pour moi, les principaux apports sont :


Merci d'avoir tenté de me faire comprendre cette notion. Mais
contrairement à mon habitude, j'avoue que je ne parviens pas à saisir la
notion, et ces intérêts.

Autant un pointeur, je comprends. Une référence, pareillement, puisque
c'est un alias de variable.
Mais les références rvalue, ... ben non... je n'arrive pas à voir ce
que c'est physiquement.

Peut-être qu'expliqué avec d'autres mots je comprendrais la notion ?
Quitte à expliquer ce qui se passe derrière (je n'ai véritablement
maîtrisé la notion de pointeur que le jour où j'ai été initié Ã
l'assembleur).

Merci à tous en tout cas !
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
  Réponse avec citation
Vieux 26/03/2008, 09h47   #12
Jean-Marc Bourguet
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: C++0X : Rvalue references

Mickaël Wolff <mickael.wolff@laposte.net> writes:

> Mais les références rvalue, ... ben non... je n'arrive pas à voir ce
> que c'est physiquement.


"Physiquement", c'est une reference. La difference est qu'il y a en gros
deux types d'expressions, celles qui peuvent se retrouver a gauche d'une
assignation (lvalue) et celles qui ne peuvent pas (rvalue). Si en C, ca
correspondait assez bien avec "celles qui designent un objet" et "celles
qui designent une valeur", en C++ ce n'est pas le cas or la notion de
reference est fortement liees a la notion de lvalue et on se retrouve sans
pouvoir lier des reference a des rvalues qui designent bien un objet(*).
Les references aux rvalues permettent de le faire avec les effets deja
decrits:
- on peut faire fonctionner certaines choses comme
fstream("/dev/tty") << "Une chaine\n";
qui ne le pouvait pas parce que l'operateur << libre demandait une
reference non constante
- on peut ajouter une notion de deplacement a la notion de copie, et
donc faire des optimisations en recuperant le contenu d'objets
temporaires ou assurer un transfert de responsabilite

A+

(*) On peut lier des references constantes a des lvalues, mais il y a un
objet temporaire qui est alors conceptuellement ajoute -- meme si le
compilateur peut l'enlever en tant qu'optimisation.

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/...ite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 20h10.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,23486 seconds with 20 queries