Friday, January 31, 2020

looser throw specifier

J'utilisais assez volontiers les descriptions de "quelles exceptions peuvent être produites par cette fonction" en Java. Nettement moins en C++. J'ai en tête que le compilateur n'était pas si fiable que ça sur ce point et que le jeu n'en vaut donc pas la chandelle. Au point qu'avec les derniers GCC, j'ai peut-être bien dû supprimer des throw(iScriptException) pour que le code de libgeds continue de fonctionner.

Mais il y a au moins un cas pour lequel ça semble fonctionner et qui mérite qu'on y réfléchisse: les destructeurs (et plus particulièrement les destructeurs d'exception).


class InvalidArgs : public LibraryException {
public:
    InvalidArgs(const std::string &detail) : 
        LibraryException(INVALID_ARG_SUBCODE, INVALID_ARG_NONSENSE, detail)
    {}
    virtual ~InvalidArgs() throw() {}
   // LibraryException has defined its own destructor unable to throw any exception.
   // we can only make this stricter when sub-classing it.
}; 

Update: Il y a une FAQ sur la norme ISO C++, qui traite justement de la question des exceptions dans les constructeurs et les destructeurs. On y explique que tout les mécanismes de la bibliothèque standard partent du principe qu'un destructeur ne peut pas lancer d'exception. Entre autres parce qu'en réaction à une exception, votre libc++ va identifier les destructeurs de tous les objets alloués sur la pile jusqu'au code du catch et les invoquer, mais libc++ ne sait généralement pas faire remonter deux exceptions à la fois.

Donc il ne faut pas laisser une exception sortir d'un destructeur, et ajouter un throw() à la déclaration de son destructeur est un bon moyen que le compilateur nous y force. En particulier si on définit ça au sommet d'une hiérarchie de classes, auquel cas le compilo va aussi nous avertir si on essaye d'assouplir le contrat pour faire passer plus d'exception hors d'une méthode-fille que ne le permettait la méthode-parent.

(merci à hg grep pour avoir retrouvé les anciennes lignes où j'avais des throw(xxx). C'est un bon complément mercurial à hg annotate quand on cherche quelque-chose qui a disparu plutôt que le moment où quelque-chose a été introduit.)

No comments: