• [^] # Re: finally

    Posté par (site web personnel, Mastodon) . En réponse à la dépêche Peuch-peuch Cinq Cinq, pour PHP 5.5. Évalué à 2. Dernière modification le 03 juillet 2013 à 12:00.

    Prenons un exemple. Imaginons une classe qui prend en charge l'ouverture d'un fichier, et la gestion de son buffer. L'ouverture du fichier est fainéante, l'écriture aussi, et la fonction close lance l'écriture du buffer en dernier ressort. Une exception io_error est lancée lorsqu'une erreur d'écriture est détectée :

    // c++ -o throwing_close{,.cpp} --std=c++11
    #include <iostream>
    #include <string>
    namespace my_ns
    {
     class io_error
     {
     } /* class io_error */;
     class file
     {
     public:
     // Lazy opener
     static
     file const open(std::string const );
     void flush()
     {
     throw io_error();
     }
     void close()
     {
     flush();
     }
     ~file() /* file is not declared nothrow, no warranty on exception safety */
     {
     flush();
     close();
     }
     // Append content. Open in append mode if file isn't open yet
     void append(std::string const )
     {
     }
     } /* class file */;
     file const file::open(std::string const )
     {
     file new_file {};
     return new_file;
     }
    } // namespace my_ns
    int main()
    {
     std::string content {"Big content that's going to overflow the harddrive"};
     {
     auto f = my_ns::file::open("throwing_close");
     f.append(content);
     try
     {
     f.flush();
     f.close();
     }
     catch(my_ns::io_error const & e)
     {
     std::cout << "Catched exception!\n";
     }
     }
     try
     {
     auto f = my_ns::file::open("throwing_close");
     f.append(content);
     // Destructor called: an exception is thrown from dtor
     }
     catch(my_ns::io_error const & e)
     {
     std::cout << "That can't be catched\n";
     }
    }

    Le résultat sur la ligne de commande :

    mickael@laptop:~/tmp$ ./throwing_close
    Catched exception!
    terminate called after throwing an instance of 'my_ns::io_error'
    Abandon

    Alors, évidement, ici la classe est facile à repenser, si toutefois elle faisait quelque chose. Mais imagine une architecture plus complexe, où l'exception safety n'est jamais garantie, où aucune signature n'indique qu'une fonction peut lancer une exception, où la libération d'une ressource peut être complexe et entraîner moult lancement d'exception.

    Oui, il faut libérer les ressources dès qu'on le peut, ou des comportement indéfinis sont garantis (ici on notera que l'implémentation tue directement le processus qui aura tenté de lancer une exception depuis un destructeur, il n'est pas possible d'empêcher sa destruction).

    Donc non, même en utilisant un objet RAII, il n'y a pas de garantie à ce que la ressource soit libérée si une exception peut être levée lors de l'exécution d'un destructeur.