9
votes

Rethrow_Exception peut-il vraiment jeter l'objet d'exception même, plutôt qu'une copie?

Tout en examinant ce que exception_ptr fait, la norme C ++ 11 indique (18.8.5 / 7) que:

Utilisation de Rethrow_Exception sur Exception_PTR Les objets faisant référence à la même exception ne doivent pas introduire une course de données. [Remarque: Si Rethrow_Exception retire la même exception (plutôt qu'une copie), un accès simultané à cet objet d'exception Rethown peut introduire une course de données ...

Je ne trouve pas le cas où cette étrange "note" s'applique, car l'effet décrit de rethrow_exception est "lance: l'objet d'exception auquel P fait référence" mais 15.1 / 3, décrivant le Processus de lancement d'exception Général Mandated que "Lancer une exception Copy-Initialise un objet temporaire, appelé objet d'exception."

La note bizarre impliquerait que Rethrow_Exception saute cette initialisation de copie. Mais est-ce vraiment possible?


2 commentaires

Peut-être que ça vient de bouger?


Yup, std :: rethrow_exception ne peut pas être implémenté à l'aide d'un lancer x; expression. (Mais il est similaire à lancer; .)


3 Réponses :


2
votes

Oui, c'est possible. Le mécanisme de manutention d'exception a déjà une copie de l'objet qui a été lancé à l'origine, écurrent une mémoire de mémoire privée. En règle générale, exception_ptr est implémenté comme un pointeur intelligent qui gère un compte de référence pour cette copie.

Quant aux exigences Général , si une exigence spécifique est conflictuelle avec une exigence générale, la condition spécifique gagne.


2 commentaires

Mais les notes d'Afaik ne sont pas normatives, elle devrait donc créer la nouvelle copie mandatée.


@Twicker - Vous avez peut-être raison de préciser que cela n'est pas correctement spécifié. exception_ptr était à l'origine une extension de la bibliothèque uniquement, qui nécessitait une extension du support d'exception d'exécution mais aucune modification de la langue. Nécessitant une nouvelle copie signifierait nécessiter un moyen de stocker un pointeur sur le constructeur de copie de l'objet; Bien que cela soit techniquement réalisable, il est beaucoup plus simple de simplement réutiliser l'ancien objet. Et en pratique, il n'y a pas de différence; Vous pouvez écrire un constructeur de copie qui enregistre si cela s'appelle, mais que de côté, cela n'affecte pas de code du monde réel.



4
votes

Lorsque vous dites jette x; , l'objet d'exception a le même type que x mais est une copie.

Lorsque vous dites std :: rethrow_exception (p); , l'objet d'exception est l'objet réel qui est mentionné par le pointeur, et aucune autre copie est faite.

Il y a donc plusieurs threads réthrow dont le pointeur d'exception même (que vous êtes autorisé à copier!), ils ont tous une référence à l'objet même .


2 commentaires

Ok, ça a du sens. Néanmoins, la norme est confuse lorsqu'elle décrit le comportement de Rethrow_Exception comme "lancers: l'objet d'exception auquel P fait référence".


@ Twicker: Je pense que c'est assez clair. Il y a toujours une notion "L'objet d'exception" et std :: actuel_exception crée un pointeur sur cet objet.



3
votes

Oui, cela ressemble à une carence dans la norme. Pour une expression de jet de repère I.e. lancer; sans opérande, 15.1P8 dit:

a expression de lancement sans opérande retire l'exception actuellement manipulée. L'exception est réactivée avec l'objet d'exception existant; Aucun nouvel objet d'exception n'est créé. [...]

c'est: xxx

si la mise en oeuvre de actuelle_exception copie l'objet d'exception actuellement manipulé, il n'y a aucun moyen de dire si Rethrow_Exception Copies ou non, mais s'il fait référence à l'objet d'exception, nous pouvons vérifier: xxx

chaque implémentation que j'ai essayé sur des impressions < code> 1 1 ; 0 0 est autorisé si actuel_exception copies; 0 1 est évidemment impossible, tandis que la norme de son état actuel semble nécessiter 1 0 . Le correctif serait pour 18.8.5p10 à clarifier avec la langue similaire à 15.1P8, autorisant ou mandater rethrow_exception de ne pas copier l'objet d'exception pointé par le exception_ptr . < / p>

la plupart lance: Spécifications dans la norme Just Nom A Type ( lancers: Bad_alloc ) ou utilisez l'article indéfini (< em> lance: une exception de type ... ); les seules autres spécifications d'exception à utiliser l'article défini sont celles de futur :: get et shared_future :: get , de sorte que toute résolution devrait probablement répondre à ceux aussi bien.


1 commentaires

Après d'autres enquêtes, j'ai trouvé une question de la LWG proposant de mandater une copie dans cette affaire (numéro n ° 1369). Ils semblent s'être installé contre cela, confirmant comment les implémentations semblent se comporter. Je crois qu'une clarification comme celle que vous proposez a du sens, cependant.