Selon vous, dans quel(s) cas est il préférable d'utiliser un pointeur et
dans quel(s) cas vaut-il mieux utiliser une référence ?
(en supposant qu'on ne veux pas faire de passage par valeur pour éviter la
copie de l'objet)
En fait, je pose cette question pour le passage d'un argument et pour la
variable d'une classe (il y a donc 2 questions).
Merci
On Thu, 23 Jun 2005 17:59:37 +0200, "Pierre Lairez" wrote:
Le Thu, 23 Jun 2005 09:44:22 +0200, Andre Heinen a écrit:
On Wed, 22 Jun 2005 22:15:30 +0200, "Pierre Lairez" wrote:
A chaque fois que tu te le demande, utilise des références
Je ne dirais pas ça. Par exemple, je me souviens d'un temps où je me demandais si, dans les conteneurs de la bibliothèque standard, il valait mieux utiliser des références ou des pointeurs. Si j'avais suivi ton raisonnement, j'aurais utilisé des références, et ça n'aurait pas marché.
Si la solution avec les références ne pouvait pas fonctionner, avais-tu le choix ?
Non, mais je croyais l'avoir. Je dirais donc, non pas "dans le doute, utilise une référence", mais "dans le doute, renseigne-toi".
c'est plus sûr (les références invalides n'existent pas)
<snip>
Ce que tu as voulu dire, c'est qu'étant donné l'obligation d'initialiser une référence dès sa définition, il est plus rare d'avoir des erreurs de ce genre avec des références qu'avec des pointeurs. Elles sont donc plus sûres. Et là, naturellement, je suis entièrement d'accord avec toi.
-- André Heinen Mon e-mail, encodé ROT13: n qbg urvara ng rhebcrnayvax qbg pbz La FAQ: http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/
On Thu, 23 Jun 2005 17:59:37 +0200, "Pierre Lairez"
<pierre.lairez@wanadoo.fr> wrote:
Le Thu, 23 Jun 2005 09:44:22 +0200, Andre Heinen <nospam@nospam.invalid> a
écrit:
On Wed, 22 Jun 2005 22:15:30 +0200, "Pierre Lairez"
<pierre.lairez@wanadoo.fr> wrote:
A chaque fois que tu te le demande, utilise des références
Je ne dirais pas ça. Par exemple, je me souviens d'un temps où je me
demandais si, dans les conteneurs de la bibliothèque standard, il
valait mieux utiliser des références ou des pointeurs. Si j'avais
suivi ton raisonnement, j'aurais utilisé des références, et ça
n'aurait pas marché.
Si la solution avec les références ne pouvait pas fonctionner, avais-tu le
choix ?
Non, mais je croyais l'avoir. Je dirais donc, non pas "dans le doute,
utilise une référence", mais "dans le doute, renseigne-toi".
c'est plus sûr
(les références invalides n'existent pas)
<snip>
Ce que tu as voulu dire, c'est qu'étant donné l'obligation
d'initialiser une référence dès sa définition, il est plus rare
d'avoir des erreurs de ce genre avec des références qu'avec des
pointeurs. Elles sont donc plus sûres. Et là, naturellement, je suis
entièrement d'accord avec toi.
--
André Heinen
Mon e-mail, encodé ROT13: n qbg urvara ng rhebcrnayvax qbg pbz
La FAQ: http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/
On Thu, 23 Jun 2005 17:59:37 +0200, "Pierre Lairez" wrote:
Le Thu, 23 Jun 2005 09:44:22 +0200, Andre Heinen a écrit:
On Wed, 22 Jun 2005 22:15:30 +0200, "Pierre Lairez" wrote:
A chaque fois que tu te le demande, utilise des références
Je ne dirais pas ça. Par exemple, je me souviens d'un temps où je me demandais si, dans les conteneurs de la bibliothèque standard, il valait mieux utiliser des références ou des pointeurs. Si j'avais suivi ton raisonnement, j'aurais utilisé des références, et ça n'aurait pas marché.
Si la solution avec les références ne pouvait pas fonctionner, avais-tu le choix ?
Non, mais je croyais l'avoir. Je dirais donc, non pas "dans le doute, utilise une référence", mais "dans le doute, renseigne-toi".
c'est plus sûr (les références invalides n'existent pas)
<snip>
Ce que tu as voulu dire, c'est qu'étant donné l'obligation d'initialiser une référence dès sa définition, il est plus rare d'avoir des erreurs de ce genre avec des références qu'avec des pointeurs. Elles sont donc plus sûres. Et là, naturellement, je suis entièrement d'accord avec toi.
-- André Heinen Mon e-mail, encodé ROT13: n qbg urvara ng rhebcrnayvax qbg pbz La FAQ: http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/
kanze
Alexandre wrote:
Je n'ai jamais utilisé de donnée membre de type référence (je ne m'en vante pas, c'est comme ça). Les données membres classiques de types pointeur ne sont me semble-t-il pas transformables en références. Les contraintes sur une donnée membre référence sont telles que les cas d'utilisations sont certainement très spécifiques: la référence doit être initialisée explicitement dans le constructeur, et ne pourraêtre modifiée (l'affectation, pas l'objet référencé, bien sûr). L'objet référencé doit donc exister avant la classe et ne pourra être détruit qu'après la destruction de la classe.
un cas (il me semble) classique : un membre flux (ostream, par ex) qui est donc uniquement référencé dans la classe.
class X { std::ostream& FluxDeSortie; public: X(std::ostream& Flux):FluxDeSortie(Flux); void Print(const std::string& s) {Flux<<s;} };
X flux_console(std::cout); flux_console.Print("sortie sur console"); std::ofstream UnFichier("essai.txt"); X flux_fichier(UnFichier); flux_fichier.Print("sortie sur fichier");
Reste le problème que la classe ne supporte pas l'affectation. Qui peut être parfois genant.
Aussi, l'utilisation du pointeur nul peut être utile pour faire un flux sur rien.
(Ça ne veut pas dire que le cas ne se présente jamais. Seulement qu'en tant que member, il y a des considérations supplémentaires qui pèsent souvent pour le pointeur, par rapport au cas des paramètres.)
-- James Kanze GABI Software 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
Alexandre wrote:
Je n'ai jamais utilisé de donnée membre de type référence
(je ne m'en vante pas, c'est comme ça). Les données membres
classiques de types pointeur ne sont me semble-t-il pas
transformables en références. Les contraintes sur une donnée
membre référence sont telles que les cas d'utilisations sont
certainement très spécifiques: la référence doit être
initialisée explicitement dans le constructeur, et ne
pourraêtre modifiée (l'affectation, pas l'objet référencé,
bien sûr). L'objet référencé doit donc exister avant la
classe et ne pourra être détruit qu'après la destruction de
la classe.
un cas (il me semble) classique : un membre flux (ostream, par
ex) qui est donc uniquement référencé dans la classe.
class X
{
std::ostream& FluxDeSortie;
public:
X(std::ostream& Flux):FluxDeSortie(Flux);
void Print(const std::string& s) {Flux<<s;}
};
X flux_console(std::cout);
flux_console.Print("sortie sur console");
std::ofstream UnFichier("essai.txt");
X flux_fichier(UnFichier);
flux_fichier.Print("sortie sur fichier");
Reste le problème que la classe ne supporte pas l'affectation.
Qui peut être parfois genant.
Aussi, l'utilisation du pointeur nul peut être utile pour faire
un flux sur rien.
(Ça ne veut pas dire que le cas ne se présente jamais. Seulement
qu'en tant que member, il y a des considérations supplémentaires
qui pèsent souvent pour le pointeur, par rapport au cas des
paramètres.)
--
James Kanze GABI Software
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
Je n'ai jamais utilisé de donnée membre de type référence (je ne m'en vante pas, c'est comme ça). Les données membres classiques de types pointeur ne sont me semble-t-il pas transformables en références. Les contraintes sur une donnée membre référence sont telles que les cas d'utilisations sont certainement très spécifiques: la référence doit être initialisée explicitement dans le constructeur, et ne pourraêtre modifiée (l'affectation, pas l'objet référencé, bien sûr). L'objet référencé doit donc exister avant la classe et ne pourra être détruit qu'après la destruction de la classe.
un cas (il me semble) classique : un membre flux (ostream, par ex) qui est donc uniquement référencé dans la classe.
class X { std::ostream& FluxDeSortie; public: X(std::ostream& Flux):FluxDeSortie(Flux); void Print(const std::string& s) {Flux<<s;} };
X flux_console(std::cout); flux_console.Print("sortie sur console"); std::ofstream UnFichier("essai.txt"); X flux_fichier(UnFichier); flux_fichier.Print("sortie sur fichier");
Reste le problème que la classe ne supporte pas l'affectation. Qui peut être parfois genant.
Aussi, l'utilisation du pointeur nul peut être utile pour faire un flux sur rien.
(Ça ne veut pas dire que le cas ne se présente jamais. Seulement qu'en tant que member, il y a des considérations supplémentaires qui pèsent souvent pour le pointeur, par rapport au cas des paramètres.)
-- James Kanze GABI Software 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
kanze
Alexandre wrote:
Je pense que cette tègle ne souffre pas d'exceptions.
void destroy( MaClasse& c ) { if ( ! c.canDestroy() ) { throw CannotDestroyError ; } delete &c ; }
Je connais pas mal de programmeurs qui rechigneraient à la ligne « delete &c ». Et qui préfèreraient passer un pointeur dans ce cas-ci.
tout à fait, moi itou. En fait, si fondamentalement l'objet EST un pointeur, pourquoi passer "artificiellement" une référence ?
Mais ça veut dire quoi : fondamentalement l'objet est un pointeur ? Ici, pour l'utilisateur, il s'agit toujours des objets de type MaClasse.
par exemple, ceux qui utilisent C++ Builder savent que les objets VCL ne peuvent être construits qu'avec new. Donc qu'on ne manipule que des pointeurs. Donc passage d'un pointeur...
Tout à fait. Il y a des conventions existantes auxquelles on adhère, même si elles violent nos conventions par ailleurs. Déjà, par exemple, il y a une tradition de passer des streambuf par pointeur, et des [io]stream par référence. Or que j'ai bien des cas où je garantis que le streambuf* n'est pas nul (et ne changera pas), et j'ai aussi des cas où j'ai été obligé de passer le [io]stream par pointeur, parce qu'il pouvait être nul.
Il n'y a pas que la logique en jeu.
Et puis on peut passer un pointeur.. par référence... Exemple : on code une fonction récursive sur un parcours d'arbre, un passe une feuille (par son adresse) par référence (pour pouvoir faire un new dessus par exemple...)
En fait, c'est une autre raison d'utiliser un pointeur. On ne peut pas avoir une référence à une référence. Donc, un niveau d'indirection au maximum. (Or que c'est bien connu, la solution de tout problème, c'est d'introduire un niveau d'indirection supplémentaire.)
-- James Kanze GABI Software 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
Alexandre wrote:
Je pense que cette tègle ne souffre pas d'exceptions.
void
destroy( MaClasse& c )
{
if ( ! c.canDestroy() ) {
throw CannotDestroyError ;
}
delete &c ;
}
Je connais pas mal de programmeurs qui rechigneraient à la
ligne « delete &c ». Et qui préfèreraient passer un pointeur
dans ce cas-ci.
tout à fait, moi itou. En fait, si fondamentalement l'objet
EST un pointeur, pourquoi passer "artificiellement" une
référence ?
Mais ça veut dire quoi : fondamentalement l'objet est un
pointeur ? Ici, pour l'utilisateur, il s'agit toujours des
objets de type MaClasse.
par exemple, ceux qui utilisent C++ Builder savent que les
objets VCL ne peuvent être construits qu'avec new. Donc qu'on
ne manipule que des pointeurs. Donc passage d'un pointeur...
Tout à fait. Il y a des conventions existantes auxquelles on
adhère, même si elles violent nos conventions par ailleurs.
Déjà, par exemple, il y a une tradition de passer des streambuf
par pointeur, et des [io]stream par référence. Or que j'ai bien
des cas où je garantis que le streambuf* n'est pas nul (et ne
changera pas), et j'ai aussi des cas où j'ai été obligé de
passer le [io]stream par pointeur, parce qu'il pouvait être nul.
Il n'y a pas que la logique en jeu.
Et puis on peut passer un pointeur.. par référence... Exemple
: on code une fonction récursive sur un parcours d'arbre, un
passe une feuille (par son adresse) par référence (pour
pouvoir faire un new dessus par exemple...)
En fait, c'est une autre raison d'utiliser un pointeur. On ne
peut pas avoir une référence à une référence. Donc, un niveau
d'indirection au maximum. (Or que c'est bien connu, la solution
de tout problème, c'est d'introduire un niveau d'indirection
supplémentaire.)
--
James Kanze GABI Software
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
Je pense que cette tègle ne souffre pas d'exceptions.
void destroy( MaClasse& c ) { if ( ! c.canDestroy() ) { throw CannotDestroyError ; } delete &c ; }
Je connais pas mal de programmeurs qui rechigneraient à la ligne « delete &c ». Et qui préfèreraient passer un pointeur dans ce cas-ci.
tout à fait, moi itou. En fait, si fondamentalement l'objet EST un pointeur, pourquoi passer "artificiellement" une référence ?
Mais ça veut dire quoi : fondamentalement l'objet est un pointeur ? Ici, pour l'utilisateur, il s'agit toujours des objets de type MaClasse.
par exemple, ceux qui utilisent C++ Builder savent que les objets VCL ne peuvent être construits qu'avec new. Donc qu'on ne manipule que des pointeurs. Donc passage d'un pointeur...
Tout à fait. Il y a des conventions existantes auxquelles on adhère, même si elles violent nos conventions par ailleurs. Déjà, par exemple, il y a une tradition de passer des streambuf par pointeur, et des [io]stream par référence. Or que j'ai bien des cas où je garantis que le streambuf* n'est pas nul (et ne changera pas), et j'ai aussi des cas où j'ai été obligé de passer le [io]stream par pointeur, parce qu'il pouvait être nul.
Il n'y a pas que la logique en jeu.
Et puis on peut passer un pointeur.. par référence... Exemple : on code une fonction récursive sur un parcours d'arbre, un passe une feuille (par son adresse) par référence (pour pouvoir faire un new dessus par exemple...)
En fait, c'est une autre raison d'utiliser un pointeur. On ne peut pas avoir une référence à une référence. Donc, un niveau d'indirection au maximum. (Or que c'est bien connu, la solution de tout problème, c'est d'introduire un niveau d'indirection supplémentaire.)
-- James Kanze GABI Software 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
Alexandre
Mais ça veut dire quoi : fondamentalement l'objet est un pointeur ? Ici, pour l'utilisateur, il s'agit toujours des objets de type MaClasse.
je voulais dire : quand tu ne peux manipuler que via un pointeur, pas par une valeur (par ex les composants VCL, comme dit dans mon post précédent)
Mais ça veut dire quoi : fondamentalement l'objet est un
pointeur ? Ici, pour l'utilisateur, il s'agit toujours des
objets de type MaClasse.
je voulais dire : quand tu ne peux manipuler que via un pointeur, pas par
une valeur (par ex les composants VCL, comme dit dans mon post précédent)