1

yop,

J'essaye de faire ça : throw (except("plip"));
Mais j'ai déclaré except non copiable (constructeur de copie privé). Pourquoi ? Parce que je souhaite l'intercepter par référence : catch (const except& exception)
Le compilateur n'est pas content, parce qu'apparemment il veut faire une recopie de l'objet.

Double question :
1. comment passer cet objet par référence, sans l'allouer sur le heap, ni provoquer une copie ?
2. je peux comprendre qu'il va vouloir dépiler le frame buffer de la fonction qui lance l'exception, et donc perdre l'objet lancé. Mais pourquoi peut-on alors intercepter un objet par référence ?

Il y a quelque chose qui m'échappe dans ce mécanisme...
Merci d'avance !



Et j'aime pas les exceptions avec new...
truc = Alloc(machin);
if (!truc) {
    throw(new exception("plus de mémoire")); // AHAH même pas peur !!!!!
}

2

(throw n'étant pas une fonction, les parenthèses sont inutiles, comme pour return par exemple — mais bon, si ça te fait plaisir d'en mettre embarrassed)


Folco (./1) :
Mais pourquoi peut-on alors intercepter un objet par référence ?
https://www.viva64.com/en/w/v746/ semble avoir des explications intéressantes ^^


Après sur les détails je laisse les pro du C++ te répondre.
Folco a été invité sur ce sujet.

Un avis ?

3

(ttk grin)

Mais merci, je regarde smile

Vu. Ça ne répond pas à la question, comment envoyer l’objet sans en faire une copie.

4

(c'est pas sûr qu'on puisse justement, mais comme je disais, je laisse les pro répondre embarrassed)

5

Je suis pas un grand expert du C++ donc je comprend peut-être mal ce que tu essaie de faire, mais j'ai l’impression que tu crée l'exception dans ta fonction, sur la pile. Puis tu throw une référence a cet objet. L'envoi d'une exception déroulant le pile, la référence deviendrait de toute façon invalide, il me parait donc logique d'avoir soit à la recopier, soit la mettre sur le tas.
avatar

6

Ca me parait logique aussi. Mais c'est dommage que cet objet ne soit pas directement alloué par le compilateur dans un autre endroit (BSS ou assimilé, je ne sais pas comment ça marche).
Du reste, quand il en fait une copie, il la fait où ? Sur le tas, ce qui veut dire qu'en interne il fait l'équivalent d'un new ? Quel intérêt alors de vouloir absolument intercepter les exceptions par référence ?

7

Folco (./6) :
dommage que cet objet ne soit pas directement alloué par le compilateur dans un autre endroit
Oué mais la construction n'est pas forcément faite au moment du throw, donc ça se tient :
std::string huhu("huhu");
...
throw huhu;


Tu n'es pas obligé de catcher via une référence, mais comme expliqué sur les liens que j'ai postés (et lus en diagonale cheeky), ça a un certain nombre d'avantages.

8

Oui bon, ce lien, c'est une page pour expliquer que quand on passe un argument par valeur et non par référence, on ne modifie pas la valeur de l'objet d'origine tritop
Bon enfin, c'est pas grave, c'est pas comme si tout le monde checkait ses allocations mémoire, et qu'on réussissait à arriver au bout des capacités des ordinateurs embarrassed

9

Bah c'est toi qui demande ça :
Folco (./6) :
Quel intérêt alors de vouloir absolument intercepter les exceptions par référence ?
Pourquoi voudrais-tu qu'il y ait un intérêt magique juste parce que c'est une exception ? (ils parlent de l'objet slicing lors du second throw, etc — notamment sur https://stackoverflow.com/questions/2522299/c-catch-blocks-catch-exception-by-value-or-reference qui est indiqué sur le premier lien)

10

Je me demandais s'il n'y avait pas un intérêt autre que de pouvoir modifier le contenu de l'objet. On ne s'amuse pas à faire des tutos de trois pages pour montrer que le passage d'arguments par pointeur ou référence est différend du passage par valeur.
Si encore il montrait pourquoi passer par référence est mieux que de passer par pointeur, ça serait pas mal.
Là, j'ai l'impression qu'on enfonce en long, en large et en travers une porte ouverte. grin
Et pas la peine de parler d'exception pour expliquer le mécanisme de passage des arguments cheeky

11

Bah, il y a la spécificité du throw sans argument qui est piégeuse, tout de même.

12

Folco (./6) :
Ca me parait logique aussi. Mais c'est dommage que cet objet ne soit pas directement alloué par le compilateur dans un autre endroit (BSS ou assimilé, je ne sais pas comment ça marche).
Seule les variables statiques peuvent aller dans le BSS ou le segment de données. Les variable normales déclarées dans une fonction vont sur la pile. Les new vont sur le tas.

Folco (./6) :
Du reste, quand il en fait une copie, il la fait où ? Sur le tas, ce qui veut dire qu'en interne il fait l'équivalent d'un new ?
Très bonne question. Le plus logique me semblerait sur la pile au niveau du catch vu que ça me surprendrait que C++ se permette une allocation cachée, mais j'avoue que je n'en sait rien.
avatar

13

Après vérification, il semblerait bien que j'avais faux. Le C++ fait bien une allocation cachée sur le tas pour la valeur lancée, via la fonction de la lib standard c++ : __cxa_allocate_exception.
avatar

14

Merci beaucoup d'avoir vérifié. Et ça explique comment l'exception créée en local peut être interceptée ailleurs, hors de son scope théorique de vie.
J'avais lu il y a quelques années qu'une exception avait... une exception (désolé) de ce côté.
Et le seul moyen de garder un objet en vie est effectivement l'allocation sur le tas...

Uther (./12) :
Le plus logique me semblerait sur la pile au niveau du catch
Ca voudrait dire qu'il réserve sur la pile la place de chaque type d'objet intercepté dans le catch, mais aussi de tous leurs objets dérivés potentiels.
Côté place, ça pourrait être fait dans une union, c'est pas un problème.
Mais pour connaitre la liste des dérivés possibles, ça me parait déjà plus compliqué.