Suite à la mise à jour des machines linux, nous pouvons maintenant utiliser des compilateurs plus récents qui proposent des nouvelles fonctionnalités liées à la norme [http://fr.wikipedia.org/wiki/C%2B%2B11|C++11]]. Ces fonctionnalités sont, pour ainsi dire, toutes liées à une augmentation de la lisibilité du code (simplifications d'écriture) et une amélioration du typage des objets pour rendre la programmation plus sûre (conversions implicites plus difficiles).
Malheureusement, toutes les fonctionnalités C++11 ne sont pas implémentées dans les compilateurs actuels, même les plus récents (voir ici pour une comparaison VS11 et gcc). Pour Metafor, on doit donc se limiter à un sous ensemble de fonctionnalités pour rester portable. En pratique, parmi les compilateurs qu'on utilise, c'est le visual studio qui est le plus à la traîne, donc on va se limiter à ce que propose Microsoft concernant le C++11. Vous allez voir: c'est déjà pas mal du tout!
J'ai trouvé un article assez bien rédigé qui présente cet ensemble de nouveautés. Ci-dessous, je vous résume cet article dans le “cadre Metafor”:
Il est devenu possible, en C++11, lors de la déclaration d'une variable, de ne pas spécifier son type. On utilise dans ce cas le mot-clef auto
. Par exemple:
auto i = 0; // i est un 'int'
Le but est de raccourcir les déclarations dont le type est très long. Petit exemple tiré de Gen4:
std::list<Node *>::iterator itn; for(itn=line.nodes.begin(); itn!=line.nodes.end(); ++itn) (*itn)->container = &side;
devient
for(auto itn=line.nodes.begin(); itn!=line.nodes.end(); ++itn) (*itn)->container = &side;
Conclusion: dans Metafor, on pourrait utiliser auto
pour déclarer des itérateurs ou des types un peu bizarres, longs à écrire (templates). Evidemment, utiliser auto
pour toutes les déclarations est possible mais ce ne sera autorisé que dans Metalub!
Le pointeur NULL
peut s'écrire maintenant nullptr
. C'est un objet qui a son propre type, qui n'est pas un int
. Le but est de rendre la conversion NULL
⇔ int
plus difficile.
Conclusion: dans Metafor, tous les pointeurs NULL
devraient pouvoir être remplacés par des nullptr
. Seule exception: les appels vers des libs qu'on ne contrôle pas (Qt, VTK, BLAS, etc).
Lors d'une boucle sur un container STL, Stroustrup conseille d'utiliser std::begin()
et std::end()
dans les arguments du for
pour extraire les bornes du container. La boucle de mon exemple précédent deviendrait:
for(auto itn=std::begin(line.nodes); itn!=std::end(line.nodes); ++itn) (*itn)->container = &side;
Ca permet de surdéfinir std::begin
et std::end
pour définir des itérations plus complexes, sans pour autant dériver la classe du container.
Dans Metafor, on pourrait peut être utiliser ceci pour éliminer le code des itérateurs complexes (ElementSet
p.expl.) - à regarder de plus près… plus tard.
Comme en python, on peut écrire des fonctions lambda. Ça sert à quoi? L'utilisation la plus courante est d'éviter de créer une classe pour définir un objet-fonction qu'on ne va utiliser qu'une seule fois par la suite. Une application directe est l'utilisation des fonctions TBB pour paralléliser des boucles (le corps de la boucle peut être une fonction lambda, ce qui raccourcit l'écriture).
La boucle de l'exemple précédent devient par exemple:
std::for_each(std::begin(line.nodes), std::end(line.nodes), [&](Node *n) { n->container = &side; });
Dans Metafor, ces fonctions lambda vont permettre de nettoyer la plupart des boucles de type std::for_each
qui utilisent aujourd'hui des atrocités du type std::bind2nd(std::mem_fun_ref(…)
et les boucles TBB.
Après vous avoir expliqué comment utiliser proprement et élégamment des itérateurs, je vous explique maintenant qu'il est possible, en C++11, de simplement écrire des boucles comme on le fait en python. L'utilisation des itérateurs est alors implicite.
Le code de ma boucle-exemple devient ridiculement simple et lisible par un débutant:
for(auto n : line.nodes) n->container = &side;
J'espère que cette dernière manière d'écrire les boucles en C++ vous aura convaincu que l'utilisation de la nouvelle norme apporte quelque chose. Si on veut résumer en une seule phrase l'intérêt, on peut dire que les nouvelles fonctionnalités du C++ qui ont été retenues ici permettent d'utiliser la STL de manière simple et claire, ce qui n'était pas le cas avec l'ancienne norme où les itérateurs apparaissaient explicitement dans le code.
Je n'ai pas encore testé d'autres fonctionnalités, mais je vais le faire. Voici ce qui me semble utile à première vue parmi ce que propose le VS11 (le C++11 est bien plus que ça!):
int
. De plus, les valeurs sont définies sous la forme nom_de_l_enum.VALEUR
au lieu de valeur. Bref, comme si on mettait l'énum dans une classe ou un namespace. Je dois vérifier que SWIG les digère bien avant de les utiliser en masse dans le code.move
: ce sont des nouveaux constructeurs qui permettent par exemple de retourner des objets locaux sans effectuer une copie. Ca permet aussi de gérer efficacement les objets temporaires (on parle de “rvalues”), c'est-à-dire des objets auxquels on ne peut rien assigner et qui sont sur le point d'être détruits. L'idée est de définir un constructeur par copie qui repose sur l'hypothèse que l'objet à copier va être détruit juste après… on peut donc par exemple lui voler la mémoire qu'il a alloué. Application évidente à Metafor: ne refonte des objets Matrix où on pourrait éliminer la gestion pourrie de la mémoire liée aux objets temporaires. C'est un exercice que j'aimerais faire.unique_ptr<>
, shared_ptr<>
, etc): des “vrais” pointeurs intelligents qui permettraient peut-être de se passer à terme des compteurs de référence home-made de Metafor.Quand on passera au VS12 (Visual Studio 2013), on pourra également utiliser:
std::vector<int>
par = {1, 2, 3, 4}
, comme vous le feriez avec un int[4]… c'est beau et ce sera possible.gen4.tests
pour permettre leur exécution directe (par double-clic sous Windows, en tapant directement leur nom en ligne de commande, comme des scripts, sous linux). La difficulté est de retrouver automatiquement les binaires Metafor à utiliser. J'ai donc créé un petit module qui va rechercher l'endroit où Metafor a été compilé et l'ajoute au PYTHONPATH
avant de continuer l'exécution du script. C'est pas infaillible, mais quand ça marche, cela permet de lancer tous ces tests beaucoup plus simplement qu'avant. Et si on voulait rendre cette recherche plus subtile, il suffit d'améliorer ce module additionnel.NULL
, supprimer des objets-fonctions, etc. pour me faire la main avec la nouvelle norme. Gen4 est la partie idéale du code pour faire ça puisque j'ai utilisé énormément la STL pour coder le mailleur.Gen4App
: correction d'un plantage sous linux lié à un bug. Qt nécessite que la variable argc
passée à la QApplication
reste allouée tout au long du programme. Malheureusement, je transmettais une référence vers un objet de la pile. C'est corrigé.METAFOR_USE_TBBLOOPS
n'existe plus! Pour rappel, cette option permettait d'activer l'assemblage des vecteurs et des matrices structuraux en parallèle. Le code est maintenant compilé pour permettre l'utilisation des boucles parallèles via une commande python. Par défaut, la version parallèle n'est pas activée puisque certaines combinaisons d'éléments/algorithmes ne le supportent pas. Pour activer (à vos risques et périls) l'assemblage parallèle, utilisez:StrVectorBase.useTBB() # assemblage des vecteurs en parallèle StrMatrixBase.useTBB() # assemblage des matrices en parallèle
apps.qs.tube
utilise cette fonctionnalité. J'ai changé le maillage pour avoir un test un peu plus gros.tbb::atomic<int>
qui semble donner de bons résultats. Cet objet atomic
permet de se passer une lock et d'un mutex. Une autre application que j'ai testée dans un autre code et qui sera transposée à Metafor prochainement sera l'initialisation à la volée de variables statiques, dans des boucles parallèles.ale.testConv2D
et c'est pas terrible. Ça fonctionne, il y a un gain, mais ce n'est vraiment pas fameux pour l'instant. J'ai quelques pistes en tête pour améliorer la manière de faire actuelle, qui ne correspond pas exactement à ce que je faisais en OpenMP.-nodisplay
qui lance Matlab en ligne de commande dans une console. Les cas-tests de Yves, Philippe et Luc ont été modifiés. Faudra d'ailleurs essayer d'uniformiser cette interface qui est copiée/collée un peu partout.Pour rappel, je travaille maintenant sous Linux. Le but étant de faire du parallèle beaucoup plus facilement que sous Windows et bénéficier des packages de libs bien ficelés fournis avec le système. Installer le système et compiler Metafor à partir de rien prend environ 3 heures avec Linux (comptez 2 jours pour Windows, si Luc ne vous passe pas ses libs). Metafor sous Linux est aussi environ 10% plus rapide que sous Windows.
Revers de la médaille… c'est linux: pas de Corel, pas de Photoshop, ni d'Office… Néanmoins, je crois maintenant avoir trouvé un substitut/une alternative +/- valable pour tous les programmes couramment utilisés. Dans le pire des cas, j'utilise une virtualbox (d'autres installent des programmes windows avec Wine… j'ai évité jusqu'à présent).
Bref, si vous vouliez migrer un jour du côté fuck bilou de la force, la route est déjà balisée. Je peux vous donner des tuyaux.
— Romain BOMAN 2014/09/03 09:34