Chromium Chronicle #24: StrongAlias, IdType และ TokenType

ตอนที่ 24: โดย Łukasz Anforowicz ในเบลวิว รัฐวอชิงตัน (สิงหาคม 2021)
ตอนก่อนหน้า

คุณเห็นข้อบกพร่องในโค้ดด้านล่างไหม คุณเห็นข้อบกพร่องในการตรวจสอบโค้ดเมื่อดูเฉพาะ Callsite ไหม

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

บางครั้งประเภทเดียวกันอาจแสดงค่าจากโดเมนที่ใช้ร่วมกันไม่ได้ กรณีนี้มักเกิดขึ้นกับประเภทข้อมูลที่ไม่เจาะจง เช่น จำนวนเต็มหรือสตริง ตัวอย่างด้านบนแสดงให้เห็นว่าสิ่งนี้สามารถทำให้เกิดข้อบกพร่องได้อย่างไร โชคดีที่ //base ของ Chromium ทำให้คุณแสดงประเภทที่โดดเด่นและโดดเด่นได้ง่าย ดังนี้

#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 ยอมรับทุกประเภทเป็นประเภท "แท็ก" ตัวอย่างนี้แสดงให้เห็นว่าประเภท "แท็ก" ไม่จำเป็นต้องมีคำจำกัดความประเภทใดๆ ด้วยซ้ำ การประกาศแบบล่วงหน้าทันทีสำหรับคลาสที่ไม่มีอยู่จริงนั้นใช้งานได้ดี

ในอนาคตแทนที่จะใช้ประเภทที่ไม่เฉพาะเจาะจง (เช่น บูลีน, int, สตริง) ให้พิจารณาทางเลือกต่อไปนี้

  • ใช้ base::IdType32<TagType> แทนการใช้ int32_t เป็นตัวระบุ
  • ใช้ base::TokenType<TagType> แทน base::UnguessableToken ที่ไม่เจาะจง
  • ใช้คลาส enum แทนบูลีน (เช่น kForReload, kNotForReload แทน true, false)
  • แทนที่ประเภทอื่นๆ ที่ไม่เฉพาะเจาะจงด้วย base::StrongAlias<TagType, SomeWrappedType>