에피소드 24: 작성자: 루카스 안포로비츠, 워싱턴주 벨뷰 (2021년 8월)
이전 에피소드
아래 코드에서 버그를 찾을 수 있나요? 호출 사이트만 살펴볼 때 코드 검토에서 버그 버그가 표시되나요?
Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());
동일한 유형이 호환되지 않는 도메인의 값을 나타내는 경우도 있습니다.
일반적으로 정수 또는 문자열과 같은 비특이적인 데이터 유형에서 발생합니다.
위의 예는 이것이 어떻게 버그를 일으키는지 보여줍니다.
다행히 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
는 모든 유형을 '태그' 유형으로 허용합니다.
이 예는 '태그' 유형이 어디에도 유형 정의가 필요하지 않음을 보여줍니다. 존재하지 않는 클래스의 인플레이스 전방 선언은 잘 작동합니다.
앞으로는 특정 유형 (예: 부울, 정수, 문자열) 대신 다음과 같은 대안을 고려해 보세요.
int32_t
를 식별자로 사용하는 대신base::IdType32<TagType>
를 사용합니다.- 구체적이지 않은
base::UnguessableToken
대신base::TokenType<TagType>
를 사용합니다. - 부울 대신 enum 클래스를 사용합니다(예:
true
,false
대신kForReload
,kNotForReload
). - 기타 특수 유형을
base::StrongAlias<TagType, SomeWrappedType>
로 대체합니다.