Références, instance locale, réflexion [Résolu]

Signaler
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008
-
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008
-
Salut,

Travaillant sur un projet relativement important en ce moment, et afin d'obtenir du compilateur toutes les optimisations et sécurité de code possible, j'use et abuse des références.

J'ai fini par en placé une à un endroit qui me semblait en premier abord invalide. Le compilateur ne dit rien, et le memchecker (valgrind) non plus.

Avant de poser mon raisonnement, voici le code d'exemple :

typedef std::list ObjList.

ObjList Func(void)
{
    ObjList r;
    return r;
}

int main(void)
{
    ObjList &A = Func();
}


Ai-je bon si je dit la chose suivante ?

_ Dans la fonction main, une instance locale de type ObjList est alloué pour
réceptionner le retour de la fonction Func.
_ Une référence sur cette instance est placé en A.
_ À la sortie de la fonction main, l'instance locale de type ObjList est détruite comme toute variable locale.

Merci d'avance ;)

++

9 réponses

Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
Non ca ne fonctionne pas. Derrière une référence, c'est un pointeur, or tu essais d'initialiser une référence (ou un pointeur) sur un objet qui va etre détruit immédiatement. Pour mettre une référence, il faut que ton objet de base ait une durée de vie supérieure à ta référence, or ici ce n'est pas le cas. Le compilo doit te le dire de toute facon.
Messages postés
966
Date d'inscription
samedi 3 avril 2004
Statut
Membre
Dernière intervention
4 mars 2010
4
Euh Luthor, après test, la fonction crée une copie de l'objet dans main() (c'est normal), mais attend la fin de la fonction pour la détruire comme on s'en sert, donc il semblerait que Bombela ait raison :

code test :
class

A {
public: ~A(
void){printf(
"A Destructor\n");};};A Test(

void){A a;
return a;}
int

_tmain(
int argc, _TCHAR* argv[])
{
A& a=Test();
printf(
"Wait...\n");

return 0;
}

résultat :
A Destructor
Wait...
A Destructor
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008

Le compilateur accepte ce code sans problème (g++ 4.1 sous GNU/Linux, Visual 2005 sous Windows)... dans le cas où la référence est déclarée constante :
const A& a=Test();

J'ai fait plein de teste avec des "printf" partout dans le constructeur, destructeur, constructeur de copie, et opérateur d'affectation.

Ce que dis luthor est exacte dans le cas où A& a=Test();
Ce que dis juju12 est exacte dans le cas où const A& a=Test();

De plus l'objet retourné n'est pas copié. J'ai bien vérifié, même en désactivant les optimisations (et en déclarant "a" comme simple objet).
J'imagine que le compilateur prévoir le coup quand il voit un appelle de fonction renvoyant l'objet, et alloue d'avance l'espace dans la pile, que sera utilisé par la fonction directement. (En effet, ça beau être un paramètre de retour, il ne tient pas dans le registre rax/eax [64/32bits]).

Code :

#include

using namespace std;

struct A {
~A(void)
{
cout << "A Destructor" << endl;
}
};

A Func(void)
{
A r;
return r;
}

int main (int argc, char const* argv[])
{
A& a =Func();

cout << "main" << endl;

return 0;
}

g++ toto.cpp
toto.cpp: In function «int main(int, const char**)":
toto.cpp:20: erreur: invalid initialization of non-const reference of type «A&" from a temporary of type «A"

Alors que la même chose avec un const :
g++ toto.cpp && ./a.out
main
A Destructor

Merci à vous deux.

ps : et sinon comment on met une balise code ?
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008

Petit ajout :

Je n'ai pas testé sans la constante avec Visual 2005, peut être que cela passe ?
Le compilateur de Microsoft à toujours été plus laxiste, c'est peut être pourquoi ça marche pour juju12...
Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
int fonction()
{
    return 0;
};

int main(int argc, char * argv[])
{
    int & ref1 = fonction();
...
};

Ca ne compile pas sous VC2005 et heureusement. Par contre la version "const int & ref = fonction()" compile correctement. Ca reste un peu un mystere pour moi, pk la version "const" est acceptée et pas la version "non const". Mais on utilise très souvent ceci. Ex:

void ma_fonction(const std::string &);

Lors de l'appel, le fait que l'argument soit "const" nous permet de déclarer la variable directement lors de l'appel:
ma_fonction(std::string("coucou")); // <= chose impossible si l'argument n'est pas const.
Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
Correction, ceci compile et ca me rappelle que j'avais eu des gags avec ca:

class objet
{
public:
    objet() {}
};

objet fonction()
{
    return objet();
};

int main(int argc, char * argv[])
{
    objet & ref1 = fonction();
    const objet & ref2 = fonction();
...
};

Franchement, je trouve ca très limite de la part du compilo. Ce code compile dans le cas d'une classe, pas dans le cas d'un entier. Enfin peut etre que le mieux est d'éviter d'écrire ce genre d'abération...
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008

Tu compile avec Visual ?

Car gcc ne me permet pas de fait ça, aussi bien dans le cas d'un type de base qu'avec une classe.

J'ai eu à travailler sur du code écris dans Visual C++ pour le porter sous gcc et GNU/Linux. Visual permet apparemment tout un tas de de chose irrespectueuses des standards. Mais je crois que cela s'inscrit dans la politique de Microsoft.

Sinon bonne remarque pour le "ma_fonction(std::string("coucou"));"
C'est vrai que c'est finalement étrange que cela fonctionne dans le cas d'un const, et pas dans le cas contraire.

Bien sur, "void ma_fonction(const std::string &);" indique clairement au compilo un objet en lecture seule, donc "ma_fonction(std::string("coucou"));" est parfaitement logique.

Par contre "void ma_fonction(std::string &);" pourrait indiquer que l'objet référencer sera modifier dans la fonction... ok mais... en quoi cela concerne "ma_fonction(std::string("coucou"));" ? Car après tout l'objet est créé temporairement, modifié par ma_fonction (supposition) et détruit... Certes, c'est pas logique et c'est peut être pour ça que la compilateur n'est pas d'accord ! Qu'en pensez-vous ?

++
Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
void fonction2(objet &)
{
};

...
fonction2(objet());

Ceci est accepté par visual. En tout rigueur, ca me choque pas. L'objet est créé localement lors de l'appel de la fonction et modifiable. Mais en pratique, je vois pas l'intérêt.

Pour ceci:
objet fonction()

...
objet & ref = fonction(); // ou ceci
objet * ptr = &fonction();

Je considère ca vraiment comme un bug du compilo.
Messages postés
225
Date d'inscription
mardi 4 mars 2003
Statut
Membre
Dernière intervention
30 juillet 2008

Effectivement... Visual est à l'image de Microsoft ;)

Merci pour tous ces tests !