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!