samedi 29 novembre 2014

Test - Only If

L'on se réveille après une fête, dans une maison inconnue, sans se souvenir de rien. Partant à la découverte de la maison, l'on se retrouve dans une série d'endroits complètement surréalistes, avec pour guide un psychopathe nommé Vinny qui nous cause via des radios et qui n'arrête pas de vouloir nous tuer. Savant mix entre Dear Esther pour les décors et la faible interactivité, Portal pour la présence du guide fou, avec un petit air d'Alone In the Dark pour l'atmosphère mystérieuse, Only If est disponible gratuitement sur Steam, et vaut tout à fait le détour.

Le jeu n'est pas exempt de défauts: la difficulté est très mal dosée, et certaines séquences se passent sans presque réfléchir alors que d'autres sont ridiculement difficiles, principalement par manque d'indications sur ce que l'on est censé faire. Ainsi, il est possible de mourir de multiples fois (et de recommencer le niveau) sans vraiment avoir compris là où l'on s'est trompé. Cette approche très "old school" peut s'avérer rapidement lassante, gratuit ou pas. De plus, le scénario m'a plutôt laissé sur ma faim. J'ai trouvé l'explication finale franchement faiblarde (heureusement que quelqu'un sur Youtube a eu la bonté de rejouer la scène en ajoutant les sous-titres, parce que je n'avais vraiment pas compris grand chose au premier abord), et il n'y a pas vraiment de progression à travers les niveaux: l'on va de délire en délire, et à la fin tout est expliqué d'un coup.

Mais le soft tire son épingle du jeu via l'atmosphère tout à fait intéressante et les niveaux délirants, entre réalisme, rêve et cauchemar. Les décors sont de toute beauté, et il est agréable simplement de s'y promener. La logique, bien que franchement tordue, se tient généralement. Manquant de temps et de patience, je me suis parfois laissé à regarder les soluces, mais souvent les solutions étaient de fait trouvables, à condition de se creuser un peu les méninges.

Ah, et ça tourne sous Linux! Beaucoup de bugs graphiques, cependant, dus sans doute une fois de plus à ma config: une vieille ATI tournant avec les pilotes libres. Ça ne m'a pas empêché d'apprécier!

dimanche 16 novembre 2014

Test - The Talos Principle (demo version)

Je suis tombé complètement par hasard sur la démo du jeu "The Talos Principle", alors que je regardais ce que Steam avait à offrir ces temps-ci. Présenté comme un jeu de réflexion à la Portal, avec des graphismes plutôt accrocheurs et surtout, tournant sous Linux.

Le jeu commence dans une sorte d'île méditerranéenne, le long d'un sentier qui mène à un complexe de ruines. Grâce à de petits panneaux indicateurs, l'on comprend qu'il faut récupérer des formes géométriques rappelant Tétris dans un certain nombre de zones, dans lesquels il faut combiner différents éléments pour débloquer la forme. Il faudra par exemple utiliser une sorte d'icosaèdre posé sur trépied pour rediriger une source d'énergie vers des capteurs, ou encore brouiller des portails.

Assez rapidement, on comprend que ce monde n'est pas ce qu'il semble être. Le mélange de ruines anciennes et d'objets modernes, une voix divine qui régulièrement vient commenter nos actions, mais surtout l'on se rend compte que nos mains sont celles d'un robot, et que des terminaux permettent de converser avec une sorte d'intelligence artificielle.

Les énigmes proposent un niveau de difficulté très raisonnable, et se résolvent rapidement une fois compris les mécanismes du jeu. Certaines peuvent cependant donner un peu plus de fil à retordre si l'on n'a pas la bonne idée dès le début. Je parlais de Portal au début, et l'on retrouve des sensations similaires: des énigmes indépendantes où il faut interagir avec les objets présents, un univers qui révèle peu à peu ses secrets. Par contre, pas une trace d'humour dans The Talos Principle: au contraire, la narration, les ruines et les bribes d'information fournies sous forme d'enregistrements ou de fichiers consultables sur des consoles que l'on trouve ici et là entretiennent une atmosphère inquiétante.

Les graphismes sont tout à fait agréables, et complètement fluides avec ma configuration: une vieille ATI Radeon HD 4870 tournant avec le pilote libre radeon. Il y a cependant des bugs graphiques ici et là, qui sont sans doute liés au pilote.

Voilà en tous cas un début prometteur. Mieux que Portal? Je me permets d'en douter pour l'instant, l'absence d'humour et la mécanique des énigmes finalement peu innovante empêchera peut-être à The Talos Principle d'atteindre le status de jeu mythique. Mais cela ne m'empêchera pas de m'offrir la version complète, et qui sait, d'être convaincu!

mardi 21 octobre 2014

Les astuces d'optimisation d'Andrei Alexandrescu

La présentation d'Andrei Alexandrescu à la CPP Con vaut le détour. Contrairement à d'autres présentations, qui sont plutôt sur le thème "comment utilise-t-on le C++ chez nous", celle là présente un certain nombre de micro-optimisations dans du code très commun. Deux sujets en particulier: l'inline des constructeurs et destructeurs (réponse: ça dépend, il faut mesurer!), et l'optimisation des pointeurs à comptage de références.

Parmis les trucs proposés, il en est un qui est particulièrement subtil: la plupart des pointeurs partagés le seront finalement assez peu, c'est à dire que le compteur de référence va rarement monter très haut. Par conséquent, il est possible de chouraver deux bits au pointeur, ce qui est généralement possible grâce aux politiques d'alignement, et d'utiliser ces bits pour le comptage de références. Si par malheur le nombre de référence devient trop haut, on logge, et on arrête de compter. L'on a une fuite mémoire, mais c'est un tradeoff généralement acceptable, il suffit de redémarrer le programme régulièrement.

Chez Facebook, ce genre d'optimisations, qui font gagner des dixièmes de pour cent de performances, sont critiques: sur l'ensemble de leurs datacentres, ce sont des millions de dollars économisés.

dimanche 5 octobre 2014

Systemd

Derrière cette appellation qui me fait plutôt rigoler en français se cache un redoutable troll qui a secoué Internet. Systemd, remplacement bienvenu du vénérable sysV init avec configuration simplifiée et excellentes performances au démarrage, ou rigide usine à gaz qui veut tout faire tout en étant impossible à débugger?

C'est hier que j'ai commencé à m'y intéresser, puisque par une de ces bizarreries du système de dépendances dont Debian a le secrêt, il m'a fallu y passer pour pouvoir ré-installer mon driver d'imprimante.

La bonne nouvelle, c'est que tout marche comme avant. Le démarrage est peut-être un poil plus rapide, mais sans plus.

En revanche, le point négatif, c'est que l'on ne voit strictement rien au démarrage: 3 lignes d'init, dont 2 qui me parlent de mes partitions. En particulier, quand ext3 décide de faire un fsck, je ne vois pas la jauge. Ça ne change évidemment rien au temps réel du fsck, mais au moins, je savais si ça valait le coup de rester devant ma machine, ou si je pouvais aller me chercher un dessert.

M'enfin, c'est le sens de l'histoire, paraît-il. Je garde un œil sur la bête.

samedi 4 octobre 2014

La comète 67P dans votre Blender

Vous attachez-vous aux pérégrinations de la sonde Rosetta autour de la comète 67P? Pour ceux qui ne suivent pas, il s'agit d'une mission de l'Agence Spatiale Européenne qui consiste à envoyer une sonde s'approcher à quelques centaines de kilomètres d'une comète pour l'étudier sous toutes les coutures, et, dans quelques semaines, carrément l'aborder via une sorte de harpon. L'ESA poste continuellement de nouvelles photos, et, tout dernièrement, sur leur blog, carrément le fichier objet de la comète tel que généré à travers les multiples prises de vues du caillou.

Voilà donc la comète chargée dans Blender, et rendue sans plus de façons. Ce serait probablement le moment de ressortir les tutoriels pour afficher des fonds étoilés.

Voilà un objet sympathique pour s'amuser avec Blender. Voire tenter de modeler la sonde Rosetta qui tourne autour?

lundi 29 septembre 2014

Gcc prend ses aises

J'ai récemment ressorti OpenRailz de mes cartons, pour voir s'il compilait encore. Je lance donc comme d'hab ma commande omake -j 4. Et là, c'est le drame: en quelques minutes, ma machine est à genoux, swappe à n'en plus finir, le pointeur de souris devient saccadé... Je tue la compile, tout redevient normal. Je recommence, même punition mêmes motifs.

En y regardant de plus près, je me rends compte que chaque compilation mange à peu près 1Go de RAM. Avec 4 compilations en parallèle, c'est fini, mes 4 Go sont partis. Et tout ce qui a changé depuis la dernière fois où je compilais joyeusement cette solution, c'est la version du compilateur.

J'avais en effet entendu dire que particulièrement depuis gcc 4.8, la consommation mémoire s'était accrue, mais là, je l'ai senti en plein.

On vivra avec, parce que les fonctionnalités valent le coup. Mais moi qui me pensais à l'abri du besoin, me voilà lorgnant vers une petite mise à jour de ma RAM...

Coder efficacement avec Emacs - Sommaire et conclusion

Je remets ici la liste complète de mes tutoriels sur l'utilisation d'Emacs comme environnement de développement.

Je continue à être tout à fait satisfait de mon environnement Emacs, et sous Linux du moins, je ne me vois pas en changer. Il y a probablement moyen d'améliorer encore sa productivité, par exemple en utilisant les ctags pour faire de l'autocomplétion, mais celle-ci me semble peu utile tant qu'elle n'est pas contextuelle, et le bon vieux M-Esc / est bien plus simple pour un résultat presque aussi bon. Peut-être que la compétition renouvelée entre gcc et clang pourra nous donner de meilleurs outils d'autocomplétion ou de compilation à la volée qui s’intégreront avec Emacs. En attendant, je me contente très bien de ce que j'ai. Et le regard d'envie de mon vimeux de voisin lorsque je lance un gdb-many-windows n'a pas de prix :)

samedi 27 septembre 2014

Encore de la move semantics

J'avais déjà longuement parlé des coûteuses erreurs d'inattention liées à la move semantics lors du passage de paramètres, lorsque des objets qui paraissent parfaitement valides ne le sont plus. Je me suis fait avoir une fois de plus avant-hier. Ce n'est pas aussi terrible que la fois précédente, puisque mon test unitaire a très vite attrapé la faute, mais cela prouve qu'il est finalement assez difficile de ne pas se tromper.

J'ai donc commencé à implémenter l'idée initiale proposée par Yakk sur StackOverflow, et je nomme mes arguments abcMoved pour bien indiquer qu'il faut bien faire attention:

class Person
{
 public:
  A(std::string nameMoved, std::string addressMoved):
    _name(std::move(nameMoved)),
    _address(std::move(addressMoved)
  {
    std::cout << _name << " " << _address << std::endl;
  }

 private:
  std::string _name;
  std::string _address;
};

Avec cette manière de faire, un std::cout << nameMoved << std::endl devrait nous sauter au visage. J'essaie, et je vous en recause.

lundi 22 septembre 2014

Delegating constructors

Aujourd'hui, j'ai collé mon premier delegate constructor dans du code de production.

Jusqu'ici, je n'en avais pas vraiment ressenti le besoin: la grande majorité de mes classes n'a qu'un seul constructeur, et celles qui en ont plus ont généralement besoin de comportements très différents. Mais aujourd'hui, j'ai voulu utiliser un delegate constructor, pour rendre mon code plus facile à utiliser depuis les tests unitaires.

Dans mon cas, j'avais un constructeur qui prenait, entre autres, un gros objet, à partir duquel on retirait plusieurs petits pour les mettre dans des attributs. Le problème, c'est que ce gros objet est difficilement moquable, alors que les petits le sont facilement. De plus, je veux vraiment passer le gros objet (et pas les petits) par le constructeur, pour éviter que l'utilisateur ne s'emmêlle les pinceaux sur la manière d'extraire les petits.

Ma solution fut donc de créer un constructeur protégé qui prend les petits objets, appelé par mon constructeur principal public qui prend le gros. Pas de risques de mal utiliser la classe. Et depuis mes tests unitaires, je dérive mon objet, rend l'autre constructeur visible, et passe mes objets moqués.

C'est probablement un cas d'utilisation très particulier. Je ne pense pas avoir à réitérer l'expérience de si peu. Mais il est plaisant de trouver des cas d'utilisation qui rendent le code vraiment plus élégant.

samedi 30 août 2014

Grosse mise à jour Debian

Ça occupe! Tout d'abord, Debian est passé à Postgresql 9.4. Depuis 9.0, Postgresql fait tout ce que je veux, je n'attendais pas particulièrement cette dernière version, mais ça fait toujours plaisir d'être à jour. La mise à jour est toujours aussi triviale, et mes vieilles notes toujours d'actualité. Il faut juste ne pas se tromper de cluster.

Ensuite, quelques changements mineurs dans Médoc, avec Eliom qui passe en 4.0, et change quelques noms de module, et une en-tête manquante dans le client C++. Le commit est donc trivial.

Étrangement, sur ma machine virtuelle au boulot, la mise à jour a voulu passer à systemd, mais pas à la maison. Le passage à systemd semble s'être bien passé, mais un souci avec les "Guest Additions" de VirtualBox m'empêche d'en profiter. Je continuerai donc à utiliser notre bon vieux sysV pour un moment.

jeudi 28 août 2014

Lambdas et capture d'attributs

J'ai aujourd'hui découvert que la capture d'attributs dans une lambda peut parfois donner des résultats surprenants. Regardez donc l'innocent programme que voilà. L'idée est d'avoir une classe A qui créé une lambda, laquelle capture un attribut de type pointeur partagé. L'on s'assure que A est ensuite détruit, avant d'exécuter la lambda. Que se passe-t-il?

#include <iostream>
#include <functional>
#include <memory>

class C
{
public:
  C():
    _value("abcdef")
  {
    std::cout << "Constructor" << std::endl;
  }

  ~C()
  {
    std::cout << "Destructor" << std::endl;
  }
  
  std::string _value;
};

class A
{
public:
  A():
    _c(std::make_shared<C>())
  {
  }
  
  std::function<void()> makeLambda()
  {
    return [=]()
    {
      std::cout << "Executing the lambda" << std::endl;
      std::cout << _c->_value << std::endl;      
    };
  }
  
  std::shared_ptr<C> _c;
};

int main()
{
  std::function<void()> f;

  {
    A a;
    f = a.makeLambda();
  }
  
  f();
  
  return 0;
}

Je pensais simplement que l'attribut allait être capturé par valeur (puisqu'il y a le "=" dans ma lambda), et que donc le pointeur partagé serait copié. Or, voilà ce qui se passe lorsque l'on exécute le programme:

Constructor
Destructor
Executing the lambda

L'objet C est détruit avant l'exécution de la lambda, c'est à dire au moment de la destruction de A! C'est en plein dans le royaume de l'undefined behaviour, en l'occurence ne rien afficher, mais plus probablement un crash. En cherchant un peu, je me suis rendu compte que les attributs sont en fait capturés via le pointeur this. D'ailleurs, la lambda refuse de compiler si l'on capture explicitement _c: [_c](){...};. En revanche, le compilateur est heureux en capturant this: [this](){...};.

La solution pour faire fonctionner l'exemple est tout simple: il faut copier _c dans une variable locale à la fonction, et capturer cette variable.

  std::function<void()> makeLambda()
  {
    auto localC = _c;
    return [=]()
    {
      std::cout << "Executing the lambda" << std::endl;
      std::cout << localC->_value << std::endl;      
    };
  }

Avec cette version, le résultat est celui attendu:

Constructor
Executing the lambda
abcdef
Destructor

Attention donc à ce qui est réellement capturé!

jeudi 21 août 2014

C++14 sort de sa boite

C'est fait! À l'unanimité, le nouveau standard C++14 a été approuvé, et sera rapidement officialisé. L'annonce est parue sur le blog de l'isocpp, et a fait l'objet de jolis trolls sur Slashdot. Le C++ continue, 30 ans après, de déchaîner les passions!

Quant à moi, j'espère bientôt voir apparaître dans nos compilateurs préférés les fonctionnalités de C++17, que je me ferai un plaisir de décortiquer ici. Restez branchés!

dimanche 3 août 2014

Passage de paramètres et move semantics - Planté!

J'avais posé la question sur StackOverflow, et je n'avais pas vraiment obtenu d'autre réponse que "il faut faire attention": avec la nouvelle manière de passer les paramètres qui seront copiés, en les passant par valeur puis en les déplaçant localement, il existait un grand risque d'utiliser par erreur le paramètre après son déplacement. Et c'est ce qui m'est arrivé il y a quelques jours, me coutant 2 bonnes heures de boulot. Je vous le fait en simplifié:

class A()
{
public:
  A(std::string instance):
    _instance(std::move(instance)),
    _logPrefix("Class A : " + instance)
  {
  }

private:
  std::string _instance;
  std::string _logPrefix;
}

Avec l'ancienne convention, instance aurait été passé comme une référence constante. Avec la nouvelle, l'on déplace instance dans _instance, mais après, il ne faut surtout pas l'utiliser! Une petite erreur d'inattention, et mon _logPrefix contient n'importe quoi, ce qui cassait tout. En l’occurrence, il contenait "Class A: ", mais cela aurait tout aussi bien pu être un beau crash.

Dommage. Je finis par me demander s'il ne faut pas garder l'ancienne convention, et n'utiliser la nouvelle que dans du code qui a vraiment besoin des performances et qui a une chance de se retrouver avec une l-value dans le paramètre.

lundi 28 juillet 2014

De l'usage des lambdas

Enfin lancé à pleine vapeur sur une base de code sous g++4.8 (j'en parlais ici), je peux utiliser à fond les toutes dernières fonctionnalités du standard. En particulier, j'utilise beaucoup le range-based for, et le mot-clé override. Et, bien sûr, les lambdas.

Le cas des lambdas est intéressant. J'en rêvais pour les mettre dans mes std::for_each, lesquels avaient l'avantage d'être très brefs, en comparaison des déclarations d'itérateurs à ralonge. Les variables auto ont rendu les itérateurs bien plus agréables à utiliser, et le range-based for a fini de combler l'écart. Pour une boucle simple, un std::for_each avec un lambda est plutôt moins pratique qu'un for, en particulier, il faut rentrer begin, end, et le type du paramètre dans la lambda (en attendant les lambdas polymorphiques), à comparer à un for(auto && element : container){...}.

Reste les autres cas, en particulier les tris. Notre bon vieux std::sort veut un comparateur, et lui donner une lambda est rudement pratique. Il y a également std::binary_search dans la même veine.

C'est là que je trouve que déclarer sa lambda en dehors de l'algorithme a beaucoup d'avantages. D'une part, c'est réutilisable, s'il faut trier plusieurs conteneurs avec le même comparateur. Et d'autre part, c'est beaucoup plus lisible.

auto comparator = [](const Element & left, const Element & right)
  {return left._name < right._name;};
[...]
std::sort(c.begin(), c.end(), comparator);

Au final, cela permet de voir sa lambda plus comme un foncteur local avec une syntaxe très condensée (ce qu'était déjà le std::bind, au final, même si l'absence d'auto à l'époque rendait sa déclaration absolument épouvantable lorsque ce n'était pas un temporaire).

C'est quand même beaucoup plus joli comme cela, non?

samedi 19 juillet 2014

C++ et Microsoft Office

Que de présentations intéressantes à la CPP Con 2014, la conférence C++ qui aura lieu en Septembre. Malheureusement, je peux toujours me brosser pour que mon employeur m'envoie à Bellevue, WA (où, comme son nom l'indique, la vue est tout à fait magnifique).

En particulier, des développeurs de MS Office expliqueront comment ils développent en C++ sur Android, IOS, Windows et Mac pour tenter de garder la base de code la plus générique possible. J'espère bien qu'il y aura des vidéos.

Blender et projet Gooseberry

Je viens de voir passer sur mon compte en banque le premier prélèvement pour Gooseberry, le projet pour le prochain film de l'équipe Blender. C'est l'occasion de revenir sur l'actualité du projet

C'était le 6 mai que les responsables du projet annonçaient que malheureusement, la levée de fond n'avait pas permis de réunir suffisamment pour produire le long-métrage d'animation dont ils rêvaient. Cette campagne était très ambitieuse, et cet échec n'est donc pas vraiment une surprise. Cependant, les fonds sont suffisants pour créer un court métrage de 10 à 15 minutes. Une fois ce pilote développé, les responsables du projet reviendront sur leurs options pour transformer ce pilote en long-métrage.

Je comprends parfaitement l'envie de passer à l'échelle supérieure et de développer un long-métrage. C'est un boulot très différent et particulièrement intéressant de développer une histoire sur 1h30 plutôt que 10 minutes, et les contraintes techniques sont toutes autres (je n'ose imaginer le temps de rendu!). Mais plus personnellement, le court métrage me convient tout à fait. C'est l'espoir de voir un produit fini plus tôt, et je trouve que dans l'animation, les productions les plus courtes sont souvent les meilleures: un bon Tex Avery n'a vraiment pas à rougir en comparaison des mastodontes d'aujourd'hui type "Hotel Transylvania" ou même "Ice Age", qui commence sérieusement à s'essouffler. Je continuerai bien entendu à soutenir l'équipe Blender dans tous leurs projets.

Plus récemment, les responsables confirmaient le démarrage de la production du pilote, en particulier le travail d'écriture et le concept art.

J'avoue ne pas regarder de trop près, car je veux garder la surprise pour quand le film sera disponible!

lundi 7 juillet 2014

Goooooold linker!!!!!

C'est sous ce nom très JamesBondien que se cache un nouvel éditeur de liens, développé par Google (Gold = Google ld), avec comme but de meilleures performances lors de la compilation de grosses solutions, en remplacement du vénérable ld.

Gold est optimisé pour la vitesse. Lier de grosses bibliothèques ou de gros exécutables est donc nettement plus rapide. Sur une de nos bibliothèques mammouth (1 GB avec les informations de débug), l'édition de liens est passée de 1 minute à 40 secondes, ce qui est très agréable lorsque l'on doit effectuer cette opération des dizaines de fois par jour.

Gold permet d'effectuer l'édition de liens de manière incrémentale. En construisant le binaire de manière à laisser de l'espace autour des unités de compilation, l'éditeur de liens peut simplement remplacer le bout qui a changé et garder le reste. Cette fonctionnalité m'intéresse particulièrement: très souvent, je fais un changement trivial dans un fichier, lequel est compilé en quelques secondes. Mais c'est ensuite que je dois attendre une bonne minute que l'éditeur de liens reconstruise l'ensemble du binaire. Si la mémoire libre est rare, je perds mon cache disque, et chaque fichier objet doit être relu du disque. Autant dire, je peux aller me faire un thé, cueillette et macération incluses.

J'ai donc essayé tout ce que j'ai pu, mais malheureusement, je n'ai pas réussi à faire fonctionner le mode incrémental pour la création de bibliothèques dynamiques, alors que cela semble se passer plutôt bien lorsque l'on s'occupe directement des exécutables. Pas de bol, la grande majorité du code de notre solution est incluse dans de grosses bibliothèques dynamiques, c'était donc cette phase qui était le principal goulot d'étranglement. Il va me falloir y passer un peu plus de temps pour comprendre ce qui se passe, je n'ai pas trouvé de documentation précise sur ce point.

À noter que Gold est également l'éditeur de liens permettant de faire de l'optimisation au "link time" (LTO). C'est une fonctionnalité relativement récente de g++, qui permet d'optimiser le programme globalement, plutôt que de considérer chaque unité de compilation de manière séparée. Cela repousse une grosse partie du temps de compilation dans l'éditeur de liens. Je compte bien m'intéresser très bientôt à la LTO, attendez-vous à bientôt en avoir des nouvelles ici.

Gold est multitheadé. La version que j'ai pu tester n'avait malheureusement pas été compilée avec cette fonctionnalité, je n'ai donc pas pu vérifier si cela changeait grand chose. En particulier, j'ai cru comprendre que c'était surtout utile pour la LTO.

Hormis quelques cas particuliers où Gold ne fonctionne pas (comme par exemple les modules du noyau Linux), il n'y a pas vraiment de raisons pour ne pas y passer. Gold est devenu un projet officiel GNU, et continuera vraisemblablement à s'améliorer, là où ld a stagné pendant si longtemps.

samedi 28 juin 2014

Tableaux de taille variable

Dernière dans la liste des features C++14 dont je parlerai pour g++4.9, voici les tableaux à taille variable. Alors que jusqu'à présent, la taille d'un tableau créé sur la pile devait être une constante, g++4.9 permet de prendre une variable à la place. Le standard ne définit pas si la mémoire allouée par un tableau de taille variable doit l'être sur la pile ou sur le tas, mais l'idée, bien entendu, est de favoriser la pile et économiser ainsi une allocation coûteuse.

Voyons sans plus attendre un programme d'exemple:

#include <iostream>

int main(int argc, char ** argv)
{
  int array[argc];
  for(int index = 0; index < argc; ++index)
  {
    array[index] = index;
  }
  
  for(int index : array)
  {
    std::cout << index << std::endl;
  }

  return 0;
}

Le programme met dans un tableau la liste des entiers de 0 au nombre d'arguments de la commande. Valgrind confirme qu'aucune allocation n'a été effectuée, le tableau a donc été créé sur la pile.

==15403== HEAP SUMMARY:
==15403==     in use at exit: 0 bytes in 0 blocks
==15403==   total heap usage: 1 allocs, 1 frees, 20 bytes allocated
==15403== 
==15403== All heap blocks were freed -- no leaks are possible

Pour le fun, j'ai ré-implémenté le même programme en utilisant un std::vector, et Valgrind indique bien une allocation.

La même syntaxe étant utilisée pour les tableaux fixes et variables, je pense qu'il y a un réel risque d'utiliser l'un en pensant utiliser l'autre. D'un côté, il faudra faire attention à ne pas exploser la pile. De l'autre, il est tellement peu courant de nos jours d'utiliser un tableau directement (std::array est passé par là), que le programmeur devrait savoir à quoi s'attendre. Et parfois, économiser une microseconde dans une routine peut faire toute la différence.

samedi 21 juin 2014

Nombres en binaire

Continuons sur notre exploration de g++4.9. Toujours pas révolutionnaire, mais plutôt utile, la possibilité d'avoir des constantes binaires dans le code source. En plus de la notation 0x pour l'hexadécimal et 0 pour l'octal, voici 0b pour le binaire. Démonstration:

#include <iostream>

int main()
{
  std::cout << 130 << std::endl;
  std::cout << 0x1a << std::endl;
  std::cout << 077 << std::endl;
  std::cout << 0b1000 << std::endl;
  std::cout << 0b110'1000 << std::endl;

  return 0;
}

Le programme affiche:

130
26
63
8
104

Notons que les séparateurs de chiffres, décrits ici, fonctionnent aussi bien pour le binaire, ce qui va certainement améliorer la lisibilité.

lundi 9 juin 2014

Un Ohmmètre improvisé

Installation de luminaires, aujourd'hui. Une fois coupé le câble pour le raccourcir, surprise, les fils électriques ne sont pas marqués! Nous nous sommes retrouvés gros-Jean comme devant, avec nos trois fils d'un côté et les douilles de l'autre.

Après avoir tourné dans l'appart' à la recherche de quelque chose pour trouver le bon fil, j'ai finalement eu une idée: utiliser les fils des haut-parleurs de la hifi.

Donc, on met la musique, puis débranchage d'un des fils du haut-parleur, contact avec une des bornes dans la douille d'un côté, et contact avec un des fils de la lampe dans le haut parleur de l'autre. Essayer les deux bornes de la douille. Musique, pas musique, phase, neutre, et terre!

C'est quand même plus pratique avec un vrai ohmmètre. Ça fera un bon cadeau de Noël.

samedi 24 mai 2014

make_unique

Le support C++14 de la bibliothèque standard s'améliore également, avec l'ajout de la fonction std::make_unique. Conceptuellement, c'est difficile de faire plus simple: c'est l'équivalent de std::make_shared, mais qui retourne un pointeur unique au lieu d'un pointeur partagé.

#include <memory>
#include <string>
#include <iostream>

int main()
{
  auto val = std::make_unique<std::string>("abcd");
  std::cout << *val << std::endl;
  return 0;
}

Si vous vous souvenez, l'intérêt de make_shared est double: d'une part, permettre l'allocation du bloc de contrôle (contenant entre autres le compteur de références) en même temps que les données, ce qui permet d'augmenter les performances à l'allocation et de réduire la fragmentation mémoire, et d'autre part de rendre le code exception safe dans ce genre de cas:

f(std::shared_ptr<A>(new A), std::shared_ptr<B>(new B)

L'ordre d'exécution des différents éléments n'est pas garanti, et il est possible que le compilateur alloue A, puis B, puis construise les shared_ptr. Dans ce cas, une exception dans le constructeur de B causerait une fuite mémoire dans A. L'utilisation de make_shared résout le problème:

f(std::make_shared<A>(), std::make_shared<B>()

Avec make_unique, la première raison ne tient plus, puisqu'il n'y a pas de structure de contrôle. La deuxième raison, bien sûr, tient encore.

Mais plus généralement, le couple std::make_shared / std::make_unique permet un nouvel idiome qui vise à se débarrasser de tous les new et de tous les delete lorsqu'ils correspondent à de la mémoire gérée par nos pointeurs intelligents. Ainsi, la présence d'un new est une indication pour le programmeur qui relit le code que la section gère la mémoire d'une manière particulière (par exemple, implémentation d'un conteneur bas niveau).

jeudi 22 mai 2014

Séparateurs de chiffres

Je continue sur les fonctionnalités C++1y de g++4.9, avec le moyennement utile séparateur de chiffres. Un petit programme valant mieux que de long discours, voici la bête:

#include <iostream>

int main()
{
  std::cout << 123'456 << std::endl;
  std::cout << 1234'56 << std::endl;
  std::cout << 12345'6 << std::endl;
  std::cout << 1'23'4.5'6 << std::endl;

  return 0;
}

L'exécution donne, comme prévu:

123456
123456
123456
1234.56

L'idée est donc d'avoir la possibilité d'ajouter l'apostrophe comme séparateur de chiffres, mais pas seulement nécessairement pour les milliers: on peut les mettre n'importe où. Utile, je suppose, pour les cultures qui groupent plutôt par dizaines de milliers.

C'est très mostly harmless, même si ça alourdit un poil le standard et l'implémentation... Pour améliorer la lisibilité des constantes, pourquoi ne pas compter plutôt sur l'éditeur de texte?

lundi 5 mai 2014

Lambdas polymorphiques

G++4.9 vient de débarquer dans Debian Jessie. C'est donc l'occasion de voir ce que cette nouvelle mouture nous réserve, en particulier du côté du support de C++14. Les lambdas polymorphiques sont similaires aux fonctions templates, les paramètres génériques (spécifiés par auto) étant résolus à l'instanciation de la fonction. Voici un petit exemple:

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>


int main()
{
  std::vector<int> v = {1, 2, 3, 4, 5};
  
  std::for_each(v.begin(),
                v.end(),
                [](auto i) { std::cout << i << std::endl; }
                );
  
  auto output = std::accumulate(
                  v.begin(),
                  v.end(),
                  std::string(" == > "),
                  [](auto & acc, auto i) 
                    { return acc + std::to_string(i); }
                  );

  std::cout << output << std::endl;
  
  return 0;
}

Dans l'exemple précédent, la fonction lambda est instanciée au moment où elle est déclarée, mais l'on n'est pas obligé d'effectuer ces opérations ensemble, si l'on veut réutiliser sa lambda. Voyez l'exemple suivant: la lambda est créée (son type est auto, puisqu'il n'est pas possible de déclarer une lambda autrement qu'en la définissant), et elle est utilisée (et donc instanciée) à deux endroits.

#include <iostream>
#include <vector>
#include <algorithm>


int main()
{
  auto turn_to_pair = [](auto & left, auto & right) 
    { return std::make_pair(left, right); };
  
  auto l1 = {1, 2, 3, 4, 5};
  auto l2 = {"a", "b", "c", "d", "e"};

  std::vector<std::pair<int, std::string> > r1;
  std::vector<std::pair<std::string, int> > r2;

  std::transform(l1.begin(),
                 l1.end(),
                 l2.begin(),
                 std::back_inserter(r1),
                 turn_to_pair);

  std::transform(l2.begin(),
                 l2.end(),
                 l1.begin(),
                 std::back_inserter(r2),
                 turn_to_pair);

  return 0;
}

Au passage, si j'ai bien tout compris au post de Scott Meyers, ma lambda pourrait être encore plus générique en prenant des références universelles. Après avoir longuement cherché, je n'ai toujours pas trouvé s'il était nécessaire d'utiliser le perfect forwarding si la fonction appelée attend elle-même des références universelles, mais ça ne peut pas faire de mal. L'on écrirait alors:

  auto turn_to_pair = [](auto && left, auto && right) 
    { return std::make_pair(std::forward(left), 
                            std::forward(right)); };

mercredi 30 avril 2014

De g++4.4 à g++4.8

Je suis en train de passer un bon bout de code (environ 2 million de lignes de code) de g++4.4 à g++4.8. Rien de trop méchant, mais quelques points intéressants à noter dans l'implémentation de C++11.

Le changement qui m'a le plus impacté est celui de std::make_pair. La signature de cette fonction est passée de std::make_pair(const T & left, const U & right) à std::make_pair(T left, T right), pour finalement devenir std::make_pair(T && left, T && right). La différence est double.

D'une part, il faut surtout laisser le compilo dériver les types templates. Un std::make_pair(x, y) ne compilera pas, il faut faire std::make_pair(x, y). En effet, écrire std::make_pair<int, int> réduit les paramètres de références universelles T && à rvalue int &&, et les lvalues ne passent plus. C'est particulièrement gonflant dans les std::bind qui ne peuvent donc plus utiliser std::make_pair. Ça tombe bien, les lambdas débarquent.

D'autre part, la conversion de type ne se fait plus. Alors qu'il était possible de faire, par exemple,

std::pair<int, std::shared_ptr<std::string> > = 
std::make_pair(1, new std::string("abc"))
, la conversion de std::string * en std::shared_ptr<std::string> ne se fait plus implicitement. Il faudra donc taper
std::pair<int, std::shared_ptr<std::string> > = 
std::make_pair(1, std::make_shared<std::string>("abc"))
.

samedi 5 avril 2014

Projet Gooseberry

La fondation Blender lance un appel aux dons pour son prochain projet de film libre. Il s'agira d'un long métrage, une comédie dont le personnage principal sera un mouton. Le budget complet du projet est estimé à 3.5M d'euros, c'est à dire plus de 10 fois le budget du projet précédent, "Tears of Steel".

La fondation propose en particulier de donner 10 euros par mois pendant les 18 mois que durera le projet, ce que je me suis dépêché de faire. En particulier, cette souscription donne accès au "Blender Cloud", qui contient des tas d'informations sur l'avancée du projet. Je suis cependant tenté de ne rien regarder, histoire d'avoir la surprise le jour où le film sort!

dimanche 30 mars 2014

Overload à la joie

Bug bête, et qui traine en production depuis 1 mois!

De quoi s'agit-t-il? D'un bon vieux problème de surcharge. Simplifié à l’extrême, cela revient à ça:

#include <iostream>
#include <string>

void f(bool b)
{
  std::cout << "Boolean : " << b << std::endl;
}

void f(const std::string & str)
{
  std::cout << "String : " << str << std::endl;
}

int main()
{
  f("abc");
  return 0;
}

Parce que la conversion d'un type de base vers un autre type de base est prioritaire sur la conversion d'un type de base vers un objet via son constructeur, le compilo transforme notre char * en bool, et pas en std::string. Et c'est le drame.

vendredi 7 mars 2014

Portal 2 sous Linux

Et au suivant! Portal 2 est enfin disponible sous Linux, en version Beta. Si vous le voyez dans votre Steam, n'oubliez pas de faire un clic droit et de sélectionner "Properties" => "Betas" => pour vous ajouter à la beta. En plus des fichiers de données, Steam télécharge alors le binaire Linux. Et ça marche! Pour une béta, la qualité est tout à fait là. Sur ma machine, pourtant pas toute jeune et avec les drivers AMD libres, je fais tourner la bête avec tous les paramètres vidéo à fond, c'est beau et fluide.

I'm in space! Spaaaace!

Maintenant, le prochain que je veux voir sous Linux, c'est Skyrim!

mercredi 12 février 2014

Médoc de retour parmis les vivants!

Enfin! Il a fallu batailler pour comprendre les changements apportés à Eliom (la documentation mériterait quelques exemples supplémentaires), mais cette mise à jour est vraiment utile et rend le framework un petit peu plus facile à utiliser, une fois qu'on a compris le principe. J'ai pris quelques raccourcis pour réparer mon code, et il n'est donc pas d'une propreté à toute épreuve, mais l'ensemble du site fonctionne. Étrangement, les CSS ont eu l'air de souffrir un petit peu: en particulier, la liste des tags se déroule jusqu'à la fin de l'écran au lieu de passer à la ligne au bout du div. Également, ma section de login n'a pas l'air de prendre le style arrondi que les autres sections ont bien l'air de traiter.

Mais ce sont des détails. L'important est que Médoc soit enfin utilisable. Ouf!

Médoc dans les choux

Ces petits coquins de chez Ocsigen/Eliom, le framework de developpement Web basé sur Ocaml et qui fait fonctionner Médoc, ont fait de sérieuses mises à jour, que je n'ai pas suivies aussi assidument que je l'aurais dû... Résultat des courses, mon Médoc est par terre, et je ne peux plus accéder à mes documents, ce qui est plutôt ennuyeux pour une application qui se targue de gérer lesdits documents. C'est d'autant plus rageant que mon idée initiale, qui était de protéger les documents en les collant directement dans la base sous forme chiffrée plutôt qu'en vrac dans un dossier, protège maintenant trop bien.

J'ai découvert (un peu tard, et après m'être fait pas mal de cheveux) la page du changelog, et je suis en train de m'atteler à porter tout ça.

lundi 13 janvier 2014

Rétrospective

Bonne année à tous les lecteurs du blog!

Le moins que l'on puisse dire, c'est qu'en 2013, ce blog n'a pas été particulièrement brillant. Seulement 35 posts, c'est la pire année depuis sa création (2007 ne compte pas, ce blog étant né en Octobre). La faute au manque de temps, bien sûr, mais aussi au manque de sujets. Moins de choses à dire sur le C++, je joue moins, je modélise moins sous Blender... Et pourtant, je me suis mis au développement Web et mobile en Java, je devrais avoir des choses à dire!

Vais-je redresser la barre en 2014?

dimanche 5 janvier 2014

Eh bah ça marche!

Contre toute attente, Portal tourne comme sur des roulettes. Le son marche, c'est fluide, et ça a démarré tout seul. Chapeau aux petits gars de Valve qui ont développé une très belle plateforme. À noter que les binaires de Steam et de Portal sont en 32 bits, mais bon, je pinaille.

Et maintenant? Déjà, je ne joue plus tellement, par manque de temps, donc ça ne va pas révolutionner mon utilisation. Ensuite, je continuerai à acheter et à jouer à certains titres (du genre Skyrim) quelque soit la plateforme sous laquelle ils tournent. Mais, peut-être me laisserai-je tenter par de bons jeux tournant sous Linux, que je n'aurais pas forcément acheté sous Windows. Nous verrons!

jeudi 2 janvier 2014

Steam sur ma Debian

Je me suis enfin décidé à installer le package Steam sur ma Debian Jessie. De ma ludothèque (certes limitée), seul Portal est disponible sous Linux. C'est en train de télécharger. On verra si ça tourne avec les drivers Radeon libres. Suspense...