[C++] lifetime & unnamed class/struct

Jetez un oeil à ce minuscule programme:

[code]#include

struct Foo {
std::vector vec;
int value;
};

int main() {
Foo().vec = std::vector();
Foo().value = 123;
return 0;
}[/code]

Testé sous VS2003, ceci ne compile pas à cause de la ligne “Foo().value = 123;”, car “left operand must be l-value”. Alors…

  1. pourquoi ça passe avec le vector ?
  2. est-ce un bon principe de considérer qu’un objet sans nom “vit” jusqu’à la fin de la ligne de code où il se trouve ? dans ce cas, value existe toujours au moment de l’exécution théorique de l’assignation, non ?
  3. le standard C++ définit-il ce genre de cas ?

Et une remarque : si on chipote un peu avec d’autres opérateurs que l’assignation, on peut obtenir des résultats bizarres (mémoire corrompue mais la debug crt ne bronche pas).

Je viens de tester avec le compilo de VS2005 Beta 2 et ça ne passe ni pour l’un, ni pour l’autre. Ca ne passe pas non plus de toutes façons avec une bête struct qui possède juste le membre flottant (oulà c’est dégueulasse, ça!).

Je peux me gourrer, mais je pense que l’objet « Foo » construit à travers son constructeur par défaut sera détruit juste avant l’assignation… Après tout, il n’est construit que pour évaluer l’objet « value » (qui est un bête float), de manière à ensuite utiliser l’operateur « = » sur ce float (qui, à ce moment, viendra de se faire désallouer…). Essaye de créer un constructeur et un destructeur pour ta struct, remplace le « float » par une autre structure dans laquelle tu définis l’opérator « = », mets des breakpoints partout, et regarde dans quel ordre ça s’évalue…

Vu les différences de messages d’erreur entre VS2003 et VS2005, j’aurais tendance à dire que ce genre de truc fait partie des comportements non définis par la norme et qui, du coup, dépendent du compilateur…

int main() {
Foo().vec = std::vector();
Foo().value = 123; <<< Un struc n est pas une class d ou tu sors un constructeur deplus il te faudrai une var peut etre …
return 0;
}

Humm …

Foo bar;

bar.vec = std::vector();
bar.value = 123;
return 0;

Hum je pense que lire la base du C++ ca serai une idee …

Koubiak

[quote name=‹ koubiak › date=’ 31 May 2005, 09:40’]int main() {
Foo().vec = std::vector();
Foo().value = 123; <<< Un struc n est pas une class d ou tu sors un constructeur deplus il te faudrai une var peut etre …
return 0;
}
Humm …
Foo bar;

bar.vec = std::vector();
bar.value = 123;
return 0;
Hum je pense que lire la base du C++ ca serai une idee …
Koubiak
[right][post=« 363891 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Pas mieux, voire même ne pas commencer par ça :stuck_out_tongue:

Class et struct sont équivalents en C++ à la seule différence que par défaut tout est public dans un struct alors que c’est privé dans une class. Un struct possède donc un constructeur par défault, qui est invoqué par ().

L’invocation d’un constructeur sans nommer de variable est très fréquent, on appelle ça un « unnamed temporary », et la définition du lifetime de l’objet résultant me semble flou et je n’arrive pas à en trouver une définition claire dans le standard. Ce qui constitue donc ma question (par extension).

Par exemple, losque l’on écrit quelque chose comme std::string hello = std::string(« hello »), la r-value est un unnamed temp qui sert à invoquer l’opérateur d’assignation de l’instance hello (bien entendu cet exemple-ci n’a pas de sens, appeler directement le contructeur de hello est plus efficace).

[quote name=‹ koubiak › date=’ 31 May 2005, 08:40’]Hum je pense que lire la base du C++ ca serai une idee …
[right][post=« 363891 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Je trouve ton commentaire agressif, car c’est en fait toi qui n’a pas tout à fait compris ma question… Pour clarifier les choses, disons que j’ai tout de même une certaine expérience en C++ :stuck_out_tongue:

edit : préservage de notre beau parlé francai

Pareil que Drealmer. La différence entre un struct et une class est l’un des détails à la con les plus fantasmés du C++… tout le monde croit comme toi, alors qu’en fait, non.

Ceci dit, le problème d’origine, c’est juste par curiosité, ou c’est un vraie question? …passkeu je vois pas l’interêt de ce genre de ligne de code :stuck_out_tongue:

Bon ok, ça ressemblait à du code de noob qui pisse du C++ sans savoir ce qu’il fait. Mea culpa.

Pour ce qui est du unamed, oui on l’utilise parfois mais en r-value. Perso je ne l’ai jamais utilisé en l-value. Je ne vois pas d’application de cet usage mais pourras-tu peut-être nous en montrer.

Partant du principe que tu souhaites valoriser la valeur de l’objet de gauche, il est plus intéressant de faire appel à un constructeur en lui passant en paramètre la donnée “source”, comme ça tu as contruction + valorisation au lieu de construction et recopie.

La portée de ton objet est restreinte au bloc dans lequel tu as construit “statiquement” cet objet (à la différence du new en clair). Pour t’en convaincre, je te suggère de le faire dans une fontion autre que le main (pour simplifier le pas à pas) et de tracer au debugger le destructeur dudit objet. il faut bien sûr en déclarer un :P.

[quote name=‹ Drealmer › date=’ 31 May 2005, 16:17’]Pour clarifier les choses, disons que j’ai tout de même une certaine expérience en C++ :stuck_out_tongue:
edit : préservage de notre beau parlé francai
[right][post=« 364044 »]<{POST_SNAPBACK}>[/post][/right][/quote]

:stuck_out_tongue:

Desole d avoir paru sec mais bon vu que le probleme principale etait cache dans le titre j ai pas fait gaffe a ton probleme donc je suis partie du postulat ouuuu un noob d ou des commentaires rapides…

My fault.

koubiak so sorry

[quote name=‹ koubiak › date=’ 1 Jun 2005, 08:49’]Desole d avoir paru sec mais bon vu que le probleme principale etait cache dans le titre j ai pas fait gaffe  a ton probleme donc je suis partie du postulat ouuuu un noob d ou des commentaires rapides…
[right][post=« 364180 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Ouep je m’en suis rendu compte en relisant que mon post pouvait aussi être pris comme celui d’un gars qui n’en touche pas une et fait n’importe quoi :stuck_out_tongue: Tort partagé.

Oh, et pour le truc après le « edit », c’est en rapport au fait qu’en relisant ma réponse j’ai trouvé quelques fautes de français que j’ai corrigé, y’a rien de dirigé vers qui que ce soit.

Pour résumer sur le sujet du post, je pense que lordabdul donne la meilleure explication. Dans le cas de l’assignation, la strcture n’est en vie que le temps de l’évaluation de la l-value, et lors de l’exécution de l’assignation en elle-même ce n’est pas clair si elle l’est toujours ou pas. En résumé, autant ne pas utiliser ce genre de truc.

L’idée pour laquelle j’avais écrit cette chose à la base était de mettre un effet dans le destructeur. Plus pragmatiquement, j’avais mis un ostringstream dans la struct, et le destructeur envoyait le contenu du buffer à une méthode de log n’acceptant que des char*. Ce qui permettait donc de faire un truc de ce genre-ci:

Log().stream << « hello world » << 123 << « test » << std::endl;

Et automatiquement à la destruction de Log(), tout était forwardé d’un blog à OutputDebugString. Mais bon c’est de la bidouille, j’ai écrit un autre truc bien plus propre et basé sur les streams maintenant.