De Chromium Chronicle #24: StrongAlias, IdType en TokenType

Aflevering 24: door Łukasz Anforowicz in Bellevue, WA (augustus 2021)
Vorige afleveringen

Kun jij de bug in onderstaande code ontdekken? Zou u de bug zien in een codebeoordeling als u alleen naar de callsite kijkt?

Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());

Hetzelfde type vertegenwoordigt soms waarden uit incompatibele domeinen. Dit gebeurt meestal voor niet-specifieke gegevenstypen zoals gehele getallen of tekenreeksen. Het bovenstaande voorbeeld illustreert hoe dit bugs kan veroorzaken. Gelukkig maakt Chromium's //base het gemakkelijk om expliciete, verschillende typen te introduceren:

#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);

Afzonderlijke typen verbeteren de leesbaarheid. Bovendien vangt StrongAlias ​​typeverwisselingen op tijdens het compileren:

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);
      ^

De compiler ziet dat de typen incompatibel zijn, omdat ze een ander "tag"-type hebben. StrongAlias ​​accepteert elk type als het "tag" -type. Het voorbeeld laat zien dat het type "tag" nergens een typedefinitie nodig heeft; een in-place forward declaratie van een niet-bestaande klasse werkt prima.

Overweeg in de toekomst, in plaats van een niet-specifiek type (bijvoorbeeld een bool, een int, een string), deze alternatieven:

  • Gebruik base::IdType32<TagType> in plaats van int32_t als identificatie te gebruiken.
  • Gebruik base::TokenType<TagType> in plaats van een niet-specifieke base::UnguessableToken .
  • Gebruik een enum-klasse in plaats van een bool (bijvoorbeeld kForReload , kNotForReload in plaats van true , false ).
  • Vervang andere niet-specifieke typen door base::StrongAlias<TagType, SomeWrappedType> .