Chromium Chronicle #24:StrongAlias、IdType 和 TokenType

第 24 集:由 Łukasz Anforowicz 在华盛顿州贝尔维尤创作(2021 年 8 月)
上一集

您能在以下代码中找到 bug 吗?只查看调用点时,您在代码审核过程中会看到这个错误错误吗?

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

有时同一类型可能表示来自不兼容网域的值。 这通常适用于非特定数据类型(如整数或字符串)。上面的示例说明了这可能会导致 bug 的原因。 幸运的是,使用 Chromium 的 //base 可以轻松引入明确的独特类型:

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

拆分类型可提高可读性。此外,StrongAlias 会在编译时捕获类型混音:

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

编译器会发现类型不兼容,因为它们具有不同的“标记”类型。StrongAlias 接受任何类型作为“代码”类型。该示例表明,“标记”类型在任何位置都不需要类型定义,只要就地提交的前向声明不存在的类即可。

将来,请考虑使用以下替代类型,而不是非特定类型(例如 bool、int、字符串):

  • 使用 base::IdType32<TagType> 而不是 int32_t 作为标识符。
  • 使用 base::TokenType<TagType>,而不是非特定的 base::UnguessableToken
  • 使用枚举类而非布尔值(例如,使用 kForReloadkNotForReload,而非 truefalse)。
  • 将其他非特定类型替换为 base::StrongAlias<TagType, SomeWrappedType>