Lancer une exception de std :: call_once

La norme C ++ stipule ce qui suit à propos de l’exécution de std::call_once avec des fonctions générant des exceptions (§30.4.4.2 / 2):

2 / Effets: Une exécution de call_once qui n’appelle pas sa fonction est une exécution passive. Une exécution de call_once qui appelle sa fonction est une exécution active. Une exécution active doit appeler INVOKE (DECAY_COPY (std :: forward (func)), DECAY_COPY (std :: forward (args)) …). Si un tel appel à func lève une exception, l’exécution est exceptionnelle, sinon elle retourne. Une exécution exceptionnelle doit propager l’exception à l’appelant de call_once. Parmi toutes les exécutions de call_once pour une fois donnée_flag: au plus une doit être une exécution retournée; s’il y a une exécution en retour, ce sera la dernière exécution active; et il n’y a d’exécutions passives que s’il y a une exécution en retour. [Remarque: les exécutions passives permettent aux autres threads d’observer de manière fiable les résultats produits par l’exécution précédente renvoyée. – note de fin]

J’utilise Visual Studio 2012 et exécute le code suivant:

 void f(){ throw std::exception( "Catch me!" ); } int main( int argc, char* argv[] ){ once_flag flag; try{ call_once( flag, f ); } catch( const std::exception& e ){ cout << e.what() << endl; } return 0; } 

Mon résultat est le suivant: le code du bloc catch s’exécute et affiche le message, mais lorsque le programme existe, je reçois un appel à abort() et le message suivant est imprimé sur cout:

… \ mutex.c (38) mutex détruit alors qu’il est occupé

Est-ce censé se produire?

Est-ce censé se produire?

Non, pas vraiment. C’est un bug .

Cependant, notez le fait que VC11 n’est pas le seul sur ce point:

  • Intel ICC 13.0.1 appelle std::terminate() comme si votre exception n’était pas gérée (voir exemple en direct );
  • GCC 4.8.0 beta fonctionne probablement de la même manière, mais il n’affiche aucune sortie, il avale l’exception et met fin au programme en mode silencieux (voir exemple en direct ). [ MISE À JOUR: Ce bogue ne semble pas être reproductible dans d’autres environnements et est probablement lié à la configuration de liveworkspace.org uniquement ]

GCC 4.7.2 et Clang 3.2, en revanche, se comportent correctement.

À propos, il convient de noter que la norme C ++ (Paragraphe 18.8.1) spécifie que std::exception ne dispose que d’un constructeur par défaut et d’un constructeur de copie . Le constructeur que vous utilisez est très probablement une extension MS non portable.

Vous pouvez utiliser plutôt std::logic_error , qui dérive de std::exception et supporte un constructeur acceptant une chaîne.