Épisode 24:Łukasz Anforowicz à Bellevue, Washington (août 2021)
Épisodes précédents
Pouvez-vous repérer le bug dans le code ci-dessous ? Voudriez-vous le bug lors d'une revue de code, lorsque vous consultez uniquement le site d'appel ?
Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
Le même type peut parfois représenter des valeurs provenant de domaines incompatibles.
Cela se produit généralement pour des types de données non spécifiques tels que les entiers ou les chaînes.
L'exemple ci-dessus montre comment cela peut provoquer des bugs.
Heureusement, le fichier //base
de Chromium permet d'introduire facilement des types explicites et distincts:
#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);
Les types distincts améliorent la lisibilité.
De plus, StrongAlias
détecte les combinaisons de types 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 voit que
les types sont incompatibles,
car ils ont un "tag" différent de mots clés.
StrongAlias
accepte n'importe quel type comme "tag" de mots clés.
Cet exemple montre que le "tag" n'a même pas besoin d'une définition de type où que ce soit,
la déclaration directe sur place
d'une classe inexistante fonctionne correctement.
À l'avenir, au lieu d'un type non spécifique (par exemple, une valeur booléenne, un entier ou une chaîne), envisagez ces alternatives:
- Utilisez
base::IdType32<TagType>
au lieu d'utiliserint32_t
comme identifiant. - Utilisez
base::TokenType<TagType>
au lieu d'unbase::UnguessableToken
non spécifique. - Utiliser une classe d'énumération au lieu d'une valeur booléenne
(par exemple,
kForReload
,kNotForReload
au lieu detrue
,false
). - Remplacez d'autres types non spécifiques par
base::StrongAlias<TagType, SomeWrappedType>
.