以下代码
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1,2,3 };
if (std::count(v.begin(), v.end(), 1) > v.size() / 2) {
std::cout << "Too many\n";
}
}
发出警告:
(8,40) warning C4018: '>': signed/unsigned mismatch
这是相当合理的,因为 std::count 返回
::difference_type
并且 size() 返回 ::size
。
问题是,处理这个问题的稳健方法是什么?
在比较 ptrdiff_t 与 size_t 中讨论了如何在编译器中实现这一点,但从未说过如何安全地使用现有实现。
举例来说:
如果ptrdiff_t的秩大于size_t,则可以表示size_t的所有正值。限制 - buf <= sizeof buf poses no problems then.
否则 ptrdiff_t 可能不代表 size_t 的所有正值,然后减法限制 - buf 可能是 UB per 下面,所以比较是没有意义的。
太棒了,但是在 Win64 下我们有:
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
这是一个直接指示(如果容器不使用其他类型 ::difference_type),
size_t
值不适合 ptrdiff_t
进行安全计算(它不能将所有 size_t 值表示为正数)。
所以,这个:
if (std::count(v.begin(), v.end(), 1) > static_cast<std::vector<int>::difference_type>(v.size() / 2)) {
std::cout << "Too many\n";
}
不再安全了。
以相反的方式进行转换是不可接受的,因为它违反了上面的第一个指导。
那么,在这里塑造代码最安全的方法是什么?
我应该编写一个包装器来检查大小并返回最大类型还是有更合理和内置的东西?
问题出在有符号和无符号整数值之间。
Vector
没有无符号 ssize
函数。相反,请使用标准或范围库中的 ssize()
。
namespace rng = std::ranges;
auto main() -> int {
std::vector<int> v = { 1,2,3 };
if (std::count(v.begin(), v.end(), 1) > std::ssize(v) / 2) {
std::cout << "Too many\n";
}
return 0;
}