检查无符号整数是否没有索引的最佳实践

Best practice for checking for no index for an unsigned integer

本文关键字:最佳 索引 无符号整数 是否 检查      更新时间:2023-10-16

假设我有这个函数:

void doThings(uint8_t index) {
   if (an index is given) { ... }
}

通常,无效索引是-1,所以if语句将是if (index != -1)。如果我使用一个无符号整数来表示索引,该怎么办?为了测试-1,将函数定义更改为带符号的int会不会很傻?是否有一个普遍接受的数字表示无符号整数的"无索引"?

只需过载doThings,类似于以下内容:

void doThings(uint8_t index) {
   // do things for a given index
}
void doThings() {
   // do things for no index
}

或者,如果您只是传递函数的结果,比如findElement使用std::pair,类似于

std::pair<std::uint8_t, bool> findElement(...);
void doThings(std::pair<std::uint8_t, bool>& arg) {
    if (arg.second) {
         // do things for given element arg.first

并称之为:

doThings(findElement(...));

如果必须在同一函数中考虑这两种情况,那么更好的选择可能是只提供第二个参数。

void doThings(uint8_t index, bool indexGiven) {
   if (indexGiven) { ... }
}

然而,使用两个完全不同的函数,一个用于给定索引时,另一个用于未给定索引时。这可能会导致更干净的设计。

将函数定义更改为使用带符号整数并不愚蠢,这样您就可以检查-1了。这是一种常见的做法。

然而,如果该函数是其他人使用的定义良好且有文档记录的API的一部分,那么您可能不想将该函数更改为使用带符号的int。相反,我建议使用MAX_int(或uint8_t的0xFF)作为无效索引的标志。

我会选择Maybe类型。

// include some optional type, e.g. experimental/optional or boost/optional.hpp
using maybe_index = optional<std::uint8_t>;
void doThings(maybe_index index) {
   if (index) { ... }
   else { ... }
}

如果我需要能够表示一个索引加上一个特殊的无效状态。GCC在std::experimental中实现了所提出的std::optional,并提供了Boost版本。

问问自己哪些值对索引有效。通常,您有一个数组,数组的长度定义了有效范围。如果该数组恰好有256个元素长,则使用uint8_t的每个可能值作为有效索引,这意味着需要更多的值来表示"无效索引"。如果数组较小,则超出该数组范围的任何索引都无效,通常会使用最高值(即static_cast<uint8_t>(-1)或使用<limits>标头中的函数)。

这里已经有很多方法了,比如一个额外的标志,使用optional<uint8_t>(你应该记住,因为它适用于任何有类似需求的地方,而不仅仅是索引)或使用重载(这可能不是办法,因为这需要编译时的决定)。

相反,我会使用更大的索引类型。用于表示索引的常见类型是size_t,这是一种无符号整数类型,通常具有指针大小(即,在普通计算机上为32或64位)。如果您切换到这种方式,您将能够寻址内存中最大的阵列(而不是磁盘上的阵列!)。这样,您还可以使用static_cast<size_t>(-1)作为信号值来表示"无效索引"。