1

Yop,


Je ne comprends rien à la classe exception de la STL. Sa doc est pourtant très courte : http://www.cplusplus.com/reference/std/exception/exception/
Ce que je ne comprends pas, c'est cette manière de déclarer les fonctions :
<type> <fonction> () const throw ();

Que vient faire le "const throw ()" ici ? Comment est-il analysé ? Comment se fait-il qu'il puisse se trouver après la première paire de parenthèses ?
Il y a un const devant le throw de what(), pas devant celui du constructeur, qu'est-ce que ça signifie ?
Je veux dériver cette classe, redéfinir what(), je dois donc l'écrire "const char* what () const throw ();" ??



Voilà merci, je ne comprends pas du tout cette écriture, c'est chiant pour dériver grin

2

[code]const[/code] signifie que la fonction n’a pas d’effet de bord, et [code]throw ()[/code] signifie que la fonction ne peut lever aucune exception (cf. http://msdn.microsoft.com/en-us/library/wfa0edys(v=vs.80).aspx)
Tu as tout bon pour la syntaxe à suivre pour overrider la fonction dans une sous-classe de [code]exception[/code]
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

3

Merci beaucoup. Effectivement, ça fonctionne. C'est le genre de trucs qui m'énerve en C++, cette syntaxe bordélique et inintuitive.
Pareil, "Truc t = new (std::nothrow) Truc;"

Il sort d'où ce std::nothrow entre parenthèses ? C'est l'argument de la fonction new(), qui en fait est un opérateur, et supporte un argument en plus après sa liste d'argument ? Je trouve ça juste génial...

4

Folco (./3) :
C'est le genre de trucs qui m'énerve en C++, cette syntaxe bordélique et inintuitive.
Je te l'avais dit %p

5

Oui, je vois ça maintenant cheeky

Au fait, est-il "mieux" d'utiliser les listes d'initialisation pour un constructeur, plutôt que d'initialiser dans le corps de celui-ci ? Scott Meyers y tient beaucoup, c'est justifié (hormis le fait que ça y fait plus penser) ? C'est très usité, ou peu au contraire ?

6

Folco (./5) :
Au fait, est-il "mieux" d'utiliser les listes d'initialisation pour un constructeur, plutôt que d'initialiser dans le corps de celui-ci ?

Oui, c'est mieux. Sans ça, les membres seront initialisés par un constructeur par défaut, puis par le corps de ton constructeur, et suivant leur type ça peut être très couteux.
So much code to write, so little time.

7

Et aussi dans certains cas tu n'as pas le choix de toute façon (membres const par exemple)

8

Au passage, les déclaration throw(), caymal: http://www.gotw.ca/publications/mill22.htm
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

9

Merci bien pour tout. smile

10

Bon, j'ai donc dérivé std::exception comme ceci :
class Except: public std::exception
{
	public:
		Except (const char* Str) throw ();
		Except operator = (Except const &);
		Except (Except const &);

		const char* what () const throw ();

	private:

		const char* str;
};

Comme vous pouvez voir, j'ai redéclaré les constructeurs de copie et d'affectation qui sont déjà définis dans la classe mère pour satisfaire aux exigences de Monsieur Meyers (switch -Weffc), qui demande de redéfinir ces constructeurs quand un membre de la classe est un pointeur. C'est donc ok de ce côté-là.

Par contre, je ne les ai pas implémentés, ces constructeurs. C'est grave ? Au final, il va faire quoi s'il veut copier un objet ? Utiliser le constructeur de recopie de std::exception ? Ai-je obligation d'implémenter ça, même si les corps de ces constructeurs seraient vides ?

Bref, je ne comprends pas les tenants et aboutissants de l'implémentation de ces constructeurs, merci d'avance de m'éclairer.

11

déclare-les avec un corps vide et privés, comme ça si tu les utilises sans t'en rendre compte ça ne compilera pas, et alors il sera temps soit de modifier ton code pour ne plus les utiliser, soit de les implémenter.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

12

J'ai essayé, je ne peux pas : le mécanisme d'un simple throw :
throw (Except ("Can't initialize SDL"));
utilise le constructeur de copie, donc ça ne compile pas s'il est privé. Par contre, ça compile s'il est public mais non implémenté.

13

En effet, si tu lances un "Except(...)" au lieu d'un "new Except(...)", il est obligé de le recopier à chaque remontée de pile. Et dans ce cas, tu as besoin du constructeur par copie, qu'il vaut mieux implémenter entièrement sinon ça va utiliser la version par défaut qui ne fait probablement pas ce que tu veux (elle va partager ton const char* entre toutes les instances).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

14

Ok, merci bien. Par contre, je capte mal, si je fais un new Except (), c'est au catch de faire le delete ? Je ne pensais pas que c'était faisable, et encore moins que ça se faisait ^^

15

Oui c'est bien ça, c'est ce qui se fait le plus souvent il me semble (ça permet d'éviter de recopier tout l'objet 50 fois, en plus de t'épargner les problèmes que tu rencontres).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

16

Sinon juste pour info tu n’as vraiment pas la possibilité d’utiliser un langage moderne ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

17

bang

(vous êtes vraiment lourds avec vos trolls)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

18

(cross)

Merci Zeph ; par contre, j'ai lu du mal de l'interception d'exceptions par pointeur. Malheureusement, je ne pige rien à toutes ces finesses du C++, j'ai déjà du mal à maitriser les mécanismes de base, alors là ça sort de mes cordes : http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.14

Sasume -> je n'ai aucune contrainte, je fais ce que je veux, parce que je code pour moi. J'ai envie de me démerder en C++ au lieu de contourner les difficultés de chaque langage en migrant vers un autre (et vers d'autres difficultés).


Au fait, on fait comment pour renvoyer une référence sur un objet, quand on est dans le constructeur d'affectation ?
"return *this;" ne convient pas (-Weffc m'envoie chier), comment fait-on ?

19

Tu fais une méthode int* GetRef(){return *this;} que tu appelles juste après la construction.

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

20

Merci !

21

Folco (./18) :
Merci Zeph ; par contre, j'ai lu du mal de l'interception d'exceptions par pointeur. Malheureusement, je ne pige rien à toutes ces finesses du C++, j'ai déjà du mal à maitriser les mécanismes de base, alors là ça sort de mes cordes : http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.14

Mouais, je trouve leur justification et leur exemple un peu bidons. Bien sûr que si tu t'amuses à lancer des exceptions de même type parfois sur la pile et parfois sur le tas, tu vas finir par te retrouver dans des situations où tu ne sais plus s'il faut libérer ou non. Mais c'est complètement débile, personne ne va se tirer une balle dans le pied comme ça (et quelqu'un le fait, je pense qu'il n'a pas attendu les exceptions pour s'inventer des problèmes).

À partir du moment où tu restes cohérent avec toi-même, je ne vois pas pourquoi lancer des exceptions par pointeur serait globalement mieux ou moins bien que de les lancer par référence.

En revanche, il y a des cas particuliers où l'une ou l'autre solution peut sembler mieux adaptée. Prenons pour exemple une exception qui contient un message d'erreur perso que tu as mis en forme au moment où l'exception a été construite (donc un message non constant). Si tu la lances par référence, tu vas être obligé de définir l'opérateur par copie, et de mettre en place soit un mécanisme de pointeur partagé soit de copier intégralement le message d'erreur, sinon chaque copie de l'exception va essayer de le libérer à la destruction, et forcément à partir de la 2eme ça va planter. Dans les deux cas, c'est coûteux, et il me semble plus simple de lancer un pointeur et de ne le libérer qu'une fois, sans se prendre la tête avec des histoires de copie.

(bon l'exemple n'est pas forcément bien choisi puisqu'on pourrait mettre le message dans une std::string, il me semble que justement elles sont paresseuses par défaut et partagent le pointeur tant que la chaîne n'est pas modifiée ; mais bref, l'idée reste la même)

[edit] En fait y'a pas mal de trucs sur ton site que je trouve complètement péremptoires, le mec prend un exemple arbitraire pour exposer sa théorie et la fait passer pour une vérité universelle, quand le problème s'applique parfois à des contextes bien plus variables que ce qu'il laisse entendre. C'est dommage parceque c'est une source d'information intéressante, mais j'ai du mal à lire les textes de gens persuadés de détenir l'unique solution.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)