OVH Cloud OVH Cloud

initialisation d'une référence constante comme paramètre de fonction

9 réponses
Avatar
Marc G
bonjour,
est-il possible d'écrire par exemple

void f(std::string const& name="")
{
//...
}
ie d'initialiser une référence constante à un objet

je crois que oui dans la mesure ou "" n'est pas du type std::string et
qu'une conversion est nécessaire

alors que
void f(std::string const& name=std::string())
{
//...
}
devrait être interdit (mais mon compilateur l'accepte)

je ne trouve pas de réponse "certaine" à ma question sur internet , ni dans
mes docs.
Merci à vous

9 réponses

Avatar
Jean-Marc Bourguet
"Marc G" writes:

bonjour,
est-il possible d'écrire par exemple

void f(std::string const& name="")
{
//...
}
ie d'initialiser une référence constante à un objet


Oui.

je crois que oui dans la mesure ou "" n'est pas du type std::string et
qu'une conversion est nécessaire

alors que
void f(std::string const& name=std::string())
{
//...
}
devrait être interdit (mais mon compilateur l'accepte)


Je ne vois pas pourquoi ça devrait être interdit. Dans les deux cas, on
lie une référence constante à un temporaire.

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
Marc G
Je ne vois pas pourquoi ça devrait être interdit. Dans les deux cas, on
lie une référence constante à un temporaire.


je croyais que si on écrit
std::string const& ref=std::string("test");
ref référence un temporaire détruit par la suite ?

Avatar
kanze
Marc G wrote:
Je ne vois pas pourquoi ça devrait être interdit. Dans les
deux cas, on lie une référence constante à un temporaire.


je croyais que si on écrit
std::string const& ref=std::string("test");
ref référence un temporaire détruit par la suite ?


Certainement, mais dans le cas précis où le temporaire a servi à
directement initialisé une référence (qui ne peut être que
const), « la suite », c'est quand la référence cesse
d'exister, et non à la fin de l'expression complète, comme
d'habitude.

--
James Kanze (GABI Software) email:
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
meow
Je me permets de m'immiscer dans la discussion. Je comprends la
question (qui m'intéresse), mais je ne suis pas certain de comprendre
la réponse.

Si je comprends bien ce que dit Marc :

std::string const& ref=std::string("test");
std::cout<<ref<<std::endl;

à la première ligne j'initialise ma référence avec un
"temporaire"... Du coups, ref est un pointeur déréférencé vers une
plage mémoire déjà "libérée" à la seconde ligne. Avec un peu de
bol il y restera quelque chose de cohérent, mais ce n'est pas garanti.


Et si je comprends bien ce que dit Kanze :

Le compilateur est intelligent, il sait repérer lorsqu'on initialise
une référence avec un temporaire, du coup il fait du temporaire une
sorte de "variable locale orpheline"; Et la portée de cette variable
est celle de la référence.
Avatar
kanze
meow wrote:
Je me permets de m'immiscer dans la discussion. Je comprends la
question (qui m'intéresse), mais je ne suis pas certain de comprendre
la réponse.

Si je comprends bien ce que dit Marc :

std::string const& ref=std::string("test");
std::cout<<ref<<std::endl;

à la première ligne j'initialise ma référence avec un
"temporaire"... Du coups, ref est un pointeur déréférencé vers une
plage mémoire déjà "libérée" à la seconde ligne. Avec un peu de
bol il y restera quelque chose de cohérent, mais ce n'est pas garanti.

Et si je comprends bien ce que dit Kanze :

Le compilateur est intelligent, il sait repérer lorsqu'on initialise
une référence avec un temporaire, du coup il fait du temporaire une
sorte de "variable locale orpheline"; Et la portée de cette variable
est celle de la référence.


C'est à peu près ça. Formellement, évidemment, on ne compte pas
sur l'intelligence du compilateur. La norme spécifie la durée de
vie d'un temporaire, d'une façon assez rigueureuse. La règle
générale, c'est que la temporaire dure jusqu'à la fin de
l'expression complète dans laquelle il a été créé (et que s'il y
a plusieurs temporaires, ils seront detruits dans l'ordre
inverse de leur construction). Le cas où on initialise une
référence avec un temporaire, en revanche, est une exception ;
la durée de vie du temporaire est étendue à la durée de vie de
la référence.

Il faut noter que seulement le temporaire qui sert à
l'initialisation a la durée de vie prolongée ; d'autres
temporaires dans l'expression d'initialisation seront detruits à
la fin de l'expression complète, comme d'habitude. Et que la
règle n'est pas transitive ; initialiser une référence avec une
référence qui elle a été initialisée avec un temporaire n'a
aucun effet sur la durée de vie du temporaire. Et que
finalement, cette exceptions (et les exceptions en général) ne
peuvent jamais raccourcir la durée de vie d'un temporaire. Si la
référence initialisée est le paramètre d'une fonction, par
exemple, la référence cesse d'exister dès qu'on revient de la
fonction, mais le destructeur du temporaire ne serait appelé
qu'à la fin de l'expression complète.

--
James Kanze (GABI Software) email:
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
meow
Ok, merci pour ces précisions

Si la référence initialisée est le paramètre d'une fonction,
par exemple,


...Tu lis dans mes pensées, c'est la question que j'allais poser en
lisant ta réponse :)

Avatar
jalina
Je me permets de m'immiscer dans la discussion. Je comprends la
question (qui m'intéresse), mais je ne suis pas certain de comprendre
la réponse.

Si je comprends bien ce que dit Marc :

std::string const& ref=std::string("test");
std::cout<<ref<<std::endl;

à la première ligne j'initialise ma référence avec un
"temporaire"... Du coups, ref est un pointeur déréférencé vers une
plage mémoire déjà "libérée" à la seconde ligne. Avec un peu de
bol il y restera quelque chose de cohérent, mais ce n'est pas garanti.


Et si je comprends bien ce que dit Kanze :

Le compilateur est intelligent, il sait repérer lorsqu'on initialise
une référence avec un temporaire, du coup il fait du temporaire une
sorte de "variable locale orpheline"; Et la portée de cette variable
est celle de la référence.



Example:

#include <iostream>

class A {
public:
A() { std::cout << "A::A()n"; }
virtual ~A() { std::cout << "A::~An"; }
void doIt() const { std::cout << "A::doit()n"; }
};

int main()
{
{
A const& ref = A();
ref.doIt();
}
std::cout << "Donen";
}


Résultat:

A::A()
A::doit()
A::~A
Done

Avatar
Lahsen
bonjour,
est-il possible d'écrire par exemple

void f(std::string const& name="")
{
//...
}
ie d'initialiser une référence constante à un objet

je crois que oui dans la mesure ou "" n'est pas du type std::string et
qu'une conversion est nécessaire

alors que
void f(std::string const& name=std::string())
{
//...
}
devrait être interdit (mais mon compilateur l'accepte)

je ne trouve pas de réponse "certaine" à ma question sur internet , ni dans
mes docs.
Merci à vous




La référence est un alias d'un objet et pas un pointeur.

L'instruction:
T t = u;
est une initialisation par le constructeur de copie ( à ne pas confondre
avec affectation. En dépit de la présence du signe =, l'instruction T t
= u; n'appelle pas T::operateur=() )

Il est préférable d'employer une initialisation de type T t(u).

Dans ta fonction
f(std::string const& name=std::string())
name est un alias (référence constante ) d'un objet string construit par
copie et transmis à la fonction f. Elle a une durée de vie dans la
portée de f.

Avatar
James Kanze
Lahsen wrote:

est-il possible d'écrire par exemple

void f(std::string const& name="")
{
//...
}
ie d'initialiser une référence constante à un objet

je crois que oui dans la mesure ou "" n'est pas du type
std::string et qu'une conversion est nécessaire

alors que
void f(std::string const& name=std::string())
{
//...
}
devrait être interdit (mais mon compilateur l'accepte)

je ne trouve pas de réponse "certaine" à ma question sur
internet , ni dans mes docs.


La référence est un alias d'un objet et pas un pointeur.


Mais en tant que paramètre ou valeur de retour, un pointeur est
à peu près la seule implémentation possible.

L'instruction:
T t = u;
est une initialisation par le constructeur de copie ( à ne pas
confondre avec affectation. En dépit de la présence du signe
=, l'instruction T t = u; n'appelle pas T::operateur=() )


C'est une initialisation de type copie. Le compilateur a le
droit (mais pas l'obligation) d'appeler le constructeur de
copie ; peu le font. (Qu'il appelle le constructeur de copie ou
non, il faut qu'il y en ait un d'accessible.)

Il est préférable d'employer une initialisation de type T t(u).


Selon les goûts. Certains préfère la forme avec =, parce qu'elle
ne prète pas à l'ambiguïté quand l'initialisateur est un
temporaire du genre MaClasse(x) (mais il y a d'autres façons à
enlever l'ambiguïté).

Dans ta fonction
f(std::string const& name=std::string())

name est un alias (référence constante ) d'un objet string construit par
copie


Ou non. Tous les compilateurs que je connais liera la référence
directement à la chaîne créée par l'invocation de string(), sans
faire de copie. Ce que tu dis est vrai dans l'abstrait, mais il
y aura bien des programmeurs qui instrumenteront le constructeur
de copie, et ensuite se posera la question pourquoi il n'est pas
appelé.

et transmis à la fonction f. Elle a une durée de vie dans la
portée de f.


Non. Elle a la durée de vie de l'expression complète d'où est
appelée la fonction. La règle spéciale qui concerne la durée de
vie d'un temporaire lié à une référence ne peut pas raccourcir
sa vie, seulement la rallonger. Quelque chose comme le suivant
est légal :

std::string const* ps ;

void
ugly( std::string const& s )
{
ps = &s ;
}

int
main()
{
ugly( "doh" ), std::cout << *ps << std::endl ;
return 0 ;
}

(Évidemment, légal ou non, ce n'est pas une chose à faire.)

--
James Kanze (GABI Software) email:
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