Bombela
Messages postés225Date d'inscriptionmardi 4 mars 2003StatutMembreDernière intervention30 juillet 2008
-
7 févr. 2008 à 18:21
Bombela
Messages postés225Date d'inscriptionmardi 4 mars 2003StatutMembreDernière intervention30 juillet 2008
-
9 févr. 2008 à 14:37
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 :
_ 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.
luhtor
Messages postés2023Date d'inscriptionmardi 24 septembre 2002StatutMembreDernière intervention28 juillet 20086 8 févr. 2008 à 18:02
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.
cs_juju12
Messages postés966Date d'inscriptionsamedi 3 avril 2004StatutMembreDernière intervention 4 mars 20104 8 févr. 2008 à 18:46
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");
Bombela
Messages postés225Date d'inscriptionmardi 4 mars 2003StatutMembreDernière intervention30 juillet 2008 8 févr. 2008 à 19:08
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
Bombela
Messages postés225Date d'inscriptionmardi 4 mars 2003StatutMembreDernière intervention30 juillet 2008 8 févr. 2008 à 19:11
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...
Vous n’avez pas trouvé la réponse que vous recherchez ?
luhtor
Messages postés2023Date d'inscriptionmardi 24 septembre 2002StatutMembreDernière intervention28 juillet 20086 8 févr. 2008 à 19:32
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.
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...
Bombela
Messages postés225Date d'inscriptionmardi 4 mars 2003StatutMembreDernière intervention30 juillet 2008 8 févr. 2008 à 20:12
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 ?
luhtor
Messages postés2023Date d'inscriptionmardi 24 septembre 2002StatutMembreDernière intervention28 juillet 20086 9 févr. 2008 à 11:52
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.