Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

STL - conteneurs : pointeurs et references

11 réponses
Avatar
Jeremie Fouche
Bonjour a tous

Bon, je souhaiterai mettre au clair la difference en terme de conception
entre l'utilisation de pointeurs et l'utilisation de references. J'utilise
personnellement la regle suivante : j'utilise toujours des references, sauf
dans les cas ou il n'y a pas forcement d'objet lors d'une recherche. Je sens
qu'il faut que je m'explique.

prenons l'exemple suivant :
Un logiciel musical :
- Plusieurs canaux d'instruments.
- Chaque canal peut contenir plusieurs notes.

class Note;
class clefNote;
class lessClefNote : public std::binary_function<const clefNote&, const
clefNote&>;

class Canal
{
...
protected:
std::map<clefNote,Note,lessClefNote> m_mapNotes;

public:
const Note* GetNote(int position, int hauteur) const;
};

class Song
{
...
protected:
std::vector<Canal> m_vectCanaux;

public:
const Canal& GetCanal(int nCanal) const;
}

La regle que je souhaite utiliser est elle adaptée ? Et peut on l'appliquer
tout le temps ?
Je souhaiterai de plus comprendre pourquoi le code suivant ne compile pas
Question deja posee le 16/08 mais sans réponse ).

#include <list>

class A
{
public:
A() {}
~A() {}

public:
int m_i;
};

typedef list<A&> listRefA;
typedef listRefA::iterator iterListRefA;

Le message d'erreur m'indique que la definition du type iterListRefA est
interdite. C'est a dire, si j'ai bien regardé le source de <list> que la
definition du type A&* est interdite. Pourtant, la definition d'une liste de
reference sur un objet est authorisée. Quelques explications ?

Merci pour tout

--
Jérémie Fouché

10 réponses

1 2
Avatar
Twxs
Jeremie Fouche wrote:
Bonjour a tous


salut

Je souhaiterai de plus comprendre pourquoi le code suivant ne compile pas

typedef list<A&> listRefA;
typedef listRefA::iterator iterListRefA;

tenter le


typedef typename listRefA::iterator iterListRefA;
ca devrait passer

Avatar
Jeremie Fouche
Fabien LE LEZ a écrit dans le message :

On Wed, 25 Aug 2004 15:46:42 +0200, "Jeremie Fouche"
:

Question deja posee le 16/08 mais sans réponse


Si mes souvenirs sont bons, il y a eu des réponses. Si ton serveur de
news ne les a pas, va voir sur
http://www.google.com/advanced_group_search?hl=en


Milles excuses ...
Je vais donc voir de ce pas.

--
Jérémie


Avatar
Fabien LE LEZ
On Wed, 25 Aug 2004 15:46:42 +0200, "Jeremie Fouche"
:

Question deja posee le 16/08 mais sans réponse


Si mes souvenirs sont bons, il y a eu des réponses. Si ton serveur de
news ne les a pas, va voir sur
http://www.google.com/advanced_group_search?hl=en

Pourtant, la definition d'une liste de
reference sur un objet est authorisée.


Non. Ou alors, c'est un bug du compilo.

Avatar
Fabien LE LEZ
On Wed, 25 Aug 2004 16:02:47 +0200, Fabien LE LEZ
:

Pourtant, la definition d'une liste de
reference sur un objet est authorisée.


Non.


Euh... En fait, j'ai un doute.
L'instanciation d'un std::list<A&> n'est pas possible, ça ne fait
aucun doute. Néanmoins, je ne sais pas jusqu'à quel point parler de
"std::list<A&>" est possible.

En tout cas,

#define MACRO_Machin std::list<A&>

est parfaitement valide ;-)


Avatar
Jean-Marc Bourguet
"Jeremie Fouche" writes:

Bon, je souhaiterai mettre au clair la difference en terme de
conception entre l'utilisation de pointeurs et l'utilisation de
references. J'utilise personnellement la regle suivante : j'utilise
toujours des references, sauf dans les cas ou il n'y a pas forcement
d'objet lors d'une recherche.


Ma regle a moi est differente: j'utilise des pointeurs sauf que je ne
veux pas devoir utiliser l'operateur &. Quand une interface force a
prendre regulierement l'adresse de variables locales ou de resultats
de fonctions, je trouve qu'il y a un probleme.

typedef list<A&> listRefA;


On ne peut pas faire des listes de references.

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++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Jeremie Fouche
Fabien LE LEZ a écrit dans le message :

On Wed, 25 Aug 2004 15:46:42 +0200, "Jeremie Fouche"
:

Question deja posee le 16/08 mais sans réponse


Si mes souvenirs sont bons, il y a eu des réponses. Si ton serveur de
news ne les a pas, va voir sur
http://www.google.com/advanced_group_search?hl=en

Pourtant, la definition d'une liste de
reference sur un objet est authorisée.


Non. Ou alors, c'est un bug du compilo.


<FABIEN>
On ne peut pas stocker une référence dans un conteneur.
En fait, alors qu'un pointeur est un objet en lui-même, une référence
n'a pas d'existence en elle-même, elle n'est qu'un alias pour une
variable. En particulier, on ne peut pas la copier, et une référence
ne peut pas être paramètre de template.


OK. En fait, je pensais qu'on ne pouvais pas faire de std::vector<A&> car
effectivement, le vecteur ne pouvais etre initialisé avec une taille donnée.
Mais pour la std::list, le probleme me semblais différent, car les elements
qui sont ajoutés sont forcement existant. Mais bien evidement, c'est une
erreur que je voie car l'objet peut etre temporaire ( créé dans la pile par
exemple ).
Merci

--
Jérémie Fouché


Avatar
kanze
Fabien LE LEZ wrote in message
news:...
On Wed, 25 Aug 2004 15:46:42 +0200, "Jeremie Fouche"
:

Pourtant, la definition d'une liste de
reference sur un objet est authorisée.


Non. Ou alors, c'est un bug du compilo.


Non, c'est un comportement indéfini. Le compilateur n'est pas obligé à
se plaindre.

--
James Kanze GABI Software http://www.gabi-soft.fr
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


Avatar
kanze
Jean-Marc Bourguet wrote in message
news:...
"Jeremie Fouche" writes:

Bon, je souhaiterai mettre au clair la difference en terme de
conception entre l'utilisation de pointeurs et l'utilisation de
references. J'utilise personnellement la regle suivante : j'utilise
toujours des references, sauf dans les cas ou il n'y a pas forcement
d'objet lors d'une recherche.


Ma regle a moi est differente: j'utilise des pointeurs sauf que je ne
veux pas devoir utiliser l'operateur &. Quand une interface force a
prendre regulierement l'adresse de variables locales ou de resultats
de fonctions, je trouve qu'il y a un probleme.


L'utilisation d'une référence implique qu'il y toujours un objet, et
toujours le même objet. Si ce n'est pas le cas, on n'a pas le choix --
il faut se servir d'un pointeur.

L'utilisation d'un pointeur implique que l'utilisateur puisse passer une
adresse. Ça ne marche pas, par exemple, pour le surcharge des
opérateurs.

Dans les autres cas, la différence est largement une question de
convention. Dans les boîtes où j'ai travaillé, j'ai vu deux grandes
conventions en ce qui concerne les paramètres :

- on utilise systèmatiquement, sauf si le client a le droit de passer
un pointeur nul, et

- on utilise un pointeur chaque fois que la fonction exige que l'objet
vie au delà de l'appel de la fonction, c-à-d par exemple, qu'elle
stocke le pointeur dans l'objet, ou que la fonction joue sur la
durée de vie de l'objet -- par exemple, si la fonction fait un
delete sur le paramètre, on passe un pointeur, et non une référence.

J'ai une faible préférence actuellement pour le premier, mais
l'importance, c'est d'en choisir un et être cohérent.

Pour les valeurs de rétour, on a à peu près les deux mêmes altérnatifs :

- on renvoie une référence, sauf si on veut retenir la possibilité de
renvoyer un pointeur nul, par exemple en cas d'échec, et

- on renvoie un pointeur aussi quand il y a transfer de la
responsibilité pour la durée de vie, c-à-d quand c'est celui qui
reçoit le pointeur qui doit faire un delete.

Ici, je constate que « delete &r » sur une référence r semble dérouter
pas mal de programmeurs ; j'ai donc prèsque toujours vu la seconde
option dans les règles de codage.

En dehors des paramètres et les valeurs de rétour, je n'utilise prèsque
jamais de références. L'utilisation d'une référence dans une classe, par
exemple, rend l'affectation impossible. Mais non la construction par
copie -- or que la plupart du temps, on veut soit les deux, soit ni l'un
ni l'autre. (Mais il y a des exceptions, et il m'arrive d'avoir des
références dans des classes entité où j'ai de toute façon supprimé la
copie.)

Il ne faut pas perdre de vue que la sémantique de copie et la sémantique
d'affectation des références n'est pas la même. C'est en fait ce qui
fait qu'on ne peut pas se servir dans une collection standard, par
exemple. Aussi, dans le cas des templates, qu'une référence à une
référence est illégale (pour l'instant, au moins), et que donc, si
jamais le template utilise un T& dans son implémentation, l'instantier
sur un type référence ne va pas marcher -- si on veut utiliser les
templates, il faut priviléger les valeurs.

Enfin, il y a des traditions dont on s'éloigne difficilement, même quand
elles sont en violation des règles ci-dessus. Pour je ne sais pas quelle
raison, par exemple, la plupart du code passe des istream et des ostream
par référence, mais les streambuf par pointeur ; il m'arrive d'en faire
autant, sans raison particulière. (Mais il m'arrive aussi de passer des
streambuf par référence, quand je veux insister sur le fait que l'appelé
reçoit bien un streambuf valable et utilisable. Dans mes streambuf
filtrants, par exemple.)

--
James Kanze GABI Software http://www.gabi-soft.fr
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


Avatar
drkm
writes:

En dehors des paramètres et les valeurs de rétour, je n'utilise prèsque
jamais de références. L'utilisation d'une référence dans une classe, par
exemple, rend l'affectation impossible. Mais non la construction par
copie -- or que la plupart du temps, on veut soit les deux, soit ni l'un
ni l'autre. (Mais il y a des exceptions, et il m'arrive d'avoir des
références dans des classes entité où j'ai de toute façon supprimé la
copie.)


Un exemple classiqe, il me semble, est une classe supprimant les
modifications faites à un objet durant sa durée de vie. Par exemple
(simplifié) :

class SavingFillChar {
public:
SavingFillChar( std::ios & stream )
: myStream( stream )
, myFill( stream.fill() ) {
}
~SavingFillChar() {
myStream.fill( myFill ) ;
}
private:
std::ios & myStream ;
char myFill ;
} ;

void f( std::ostream & os ) {
SavingFillChar( os ) ;
os.fill( '_' ) ;
// ...
}

--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html

Avatar
kanze
drkm wrote in message
news:...

writes:
En dehors des paramètres et les valeurs de rétour, je n'utilise
prèsque jamais de références. L'utilisation d'une référence dans une
classe, par exemple, rend l'affectation impossible. Mais non la
construction par copie -- or que la plupart du temps, on veut soit
les deux, soit ni l'un ni l'autre. (Mais il y a des exceptions, et
il m'arrive d'avoir des références dans des classes entité où j'ai
de toute façon supprimé la copie.)


Un exemple classiqe, il me semble, est une classe supprimant les
modifications faites à un objet durant sa durée de vie. Par exemple
(simplifié) :

class SavingFillChar {
public:
SavingFillChar( std::ios & stream )
: myStream( stream )
, myFill( stream.fill() ) {
}
~SavingFillChar() {
myStream.fill( myFill ) ;
}
private:
std::ios & myStream ;
char myFill ;
} ;

void f( std::ostream & os ) {
SavingFillChar( os ) ;
os.fill( '_' ) ;
// ...
}


Tout à fait.

C'est un peu ce que j'ai cité par la suite. Pour je ne sais quelle
raison, la tradition veut qu'on maintient des références à istream,
ostream et ios, et les pointeurs à streambuf. Dans ce cas-ci, il y a
aussi le fait que l'objet n'est pas copiable, etc., qui fait que ça ne
gène pas. Mais si je régarde des classes non-copiable qui contient un
streambuf, c'est en général un pointeur que j'utilise.

--
James Kanze GABI Software http://www.gabi-soft.fr
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


1 2