Épisode 24:de Łukasz Anforowicz à Bellevue, Washington (août 2021)
Épisodes précédents
Pouvez-vous repérer le bug dans le code ci-dessous ? Voyez-vous le bug dans un examen de code, si vous n'examinez que le site d'appel ?
Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
Un même type peut parfois représenter des valeurs provenant de domaines incompatibles.
Cela se produit généralement pour les types de données non spécifiques tels que les entiers ou les chaînes.
L'exemple ci-dessus illustre la façon dont cela peut provoquer des bugs.
Heureusement, le //base
de Chromium permet d'introduire des types distincts et explicites:
#include "base/types/strong_alias.h"
// The first template argument of StrongAlias is a "tag" type.
// The "tag" type is used to distinguish between different
// StrongAlias types.
using CommandData = base::StrongAlias<class CommandDataTag, int>;
using CommandBufferId = base::StrongAlias<class CommandBufferIdTag, int>;
Token CreateToken(CommandData command_data, CommandBufferId buffer_id);
Des types distincts améliorent la lisibilité.
De plus, StrongAlias
détecte les erreurs de type au moment de la compilation:
test.cc:456:16: error: no matching function for call to 'CreateToken'
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
^~~~~~~~~~~
test.cc:123:7: note: candidate function not viable: no known conversion from
'StrongAlias<class CommandBufferIdTag, [...]>' to
'StrongAlias<class CommandDataTag, [...]>' for 1st argument
Token CreateToken(CommandData command_data, CommandBufferId buffer_id);
^
Le compilateur constate que les types sont incompatibles, car ils ont un type de "balise" différent.
StrongAlias
accepte n'importe quel type de balise.
L'exemple montre que le type "tag" n'a même besoin d'aucune définition de type. Une déclaration avant sur place d'une classe inexistante convient parfaitement.
À l'avenir, au lieu d'utiliser un type non spécifique (par exemple, une valeur booléenne, un entier ou une chaîne), envisagez les alternatives suivantes:
- Utilisez
base::IdType32<TagType>
au lieu deint32_t
comme identifiant. - Utilisez
base::TokenType<TagType>
au lieu d'unbase::UnguessableToken
non spécifique. - Utilisez une classe d'énumération au lieu d'une valeur booléenne (par exemple,
kForReload
,kNotForReload
au lieu detrue
,false
). - Remplacez les autres types non spécifiques par
base::StrongAlias<TagType, SomeWrappedType>
.