Il est en effet fort - et a recommandé à l'attraper par const
de référence.
"e
est en fait placé sur la pile de some_function()
"
Non ce n'est pas... l'objet générée est créé dans une quelconque zone de mémoire réservée pour l'utilisation par l'exception d'un mécanisme de gestion:
[exception.jetez] 15.1/4: La mémoire de l'objet exception est affecté d'une quelconque manière, sauf comme indiqué dans 3.7.4.1. L'exception
l'objet est détruit après le dernier restant actif gestionnaire pour l'exception des sorties par tous les moyens autres que le renvoi, ou le dernier objet de type std::exception_ptr (18.8.5) qui fait référence à l'objet de l'exception est détruite, si elle est postérieure.
Si une variable locale est spécifié à l' throw
, c'est du copié-à-la si nécessaire (l'optimiseur peut être en mesure de créer directement dans ce mémoire). C'est pourquoi...
15.1/5 Lors de la levée de l'objet est un objet de classe, le constructeur sélectionné pour la copie de l'initialisation et le destructeur
doit être accessible, même si le copier/déplacer l'opération est élidée (12.8).
Si ce n'est pas cliqué, il pourrait aider à imaginer la mise en œuvre vaguement comme ceci:
// implementation support variable...
thread__local alignas(alignof(std::max_align_t))
char __exception_object[EXCEPTION_OBJECT_BUFFER_SIZE];
void some_function() {
// throw std::exception("some error message");
// IMPLEMENTATION PSEUDO-CODE:
auto&& thrown = std::exception("some error message");
// copy-initialise __exception_object...
new (&__exception_object) decltype(thrown){ thrown };
throw __type_of(thrown);
// as stack unwinds, _type_of value in register or another
// thread_local var...
}
int main(int argc, char **argv)
{
try {
some_function();
} // IMPLEMENTATION:
// if thrown __type_of for std::exception or derived...
catch (const std::exception& e) {
// IMPLEMENTATION:
// e references *(std::exception*)(&__exception_object[0]);
...
}
}