我自己坚信,在我正在处理的项目中,有符号整数是大多数情况下的最佳选择,即使其中包含的值永远不会是负数。(更简单的反向循环,更少的错误机会等,特别是对于只能保存在 0 和 20 之间的值的整数,无论如何。)
大多数出错的地方是 std::vector 的简单迭代,过去通常这曾经是一个数组,后来被更改为 std::vector。所以这些循环通常看起来像这样:
for (int i = 0; i < someVector.size(); ++i) { /* do stuff */ }
因为这种模式经常被使用,关于有符号和无符号类型之间这种比较的编译器警告垃圾邮件的数量往往会隐藏更多有用的警告。请注意,我们绝对没有超过 INT_MAX 元素的向量,并且请注意,到目前为止,我们使用了两种方法来修复编译器警告:
for (unsigned i = 0; i < someVector.size(); ++i) { /*do stuff*/ }
这通常有效,但如果循环包含任何代码,如“if (i-1 >= 0) ...”等,则可能会静默中断。
for (int i = 0; i < static_cast<int>(someVector.size()); ++i) { /*do stuff*/ }
此更改没有任何副作用,但确实使循环的可读性降低了很多。(而且打字更多。)
所以我想出了以下想法:
template <typename T> struct vector : public std::vector<T>
{
typedef std::vector<T> base;
int size() const { return base::size(); }
int max_size() const { return base::max_size(); }
int capacity() const { return base::capacity(); }
vector() : base() {}
vector(int n) : base(n) {}
vector(int n, const T& t) : base(n, t) {}
vector(const base& other) : base(other) {}
};
template <typename Key, typename Data> struct map : public std::map<Key, Data>
{
typedef std::map<Key, Data> base;
typedef typename base::key_compare key_compare;
int size() const { return base::size(); }
int max_size() const { return base::max_size(); }
int erase(const Key& k) { return base::erase(k); }
int count(const Key& k) { return base::count(k); }
map() : base() {}
map(const key_compare& comp) : base(comp) {}
template <class InputIterator> map(InputIterator f, InputIterator l) : base(f, l) {}
template <class InputIterator> map(InputIterator f, InputIterator l, const key_compare& comp) : base(f, l, comp) {}
map(const base& other) : base(other) {}
};
// TODO: similar code for other container types
您所看到的基本上是 STL 类,其返回 size_type 的方法被覆盖以仅返回“int”。需要构造函数,因为它们不是继承的。
作为开发人员,如果您在现有代码库中看到这样的解决方案,您会怎么看?
您会认为“哇,他们正在重新定义 STL,多么巨大的 WTF!”,或者您会认为这是一个很好的简单解决方案,可以防止错误并提高可读性。或者您可能更愿意看到我们花了(半天)左右的时间来更改所有这些循环以使用 std::vector<>::iterator?
(特别是如果此解决方案与禁止将无符号类型用于原始数据(例如无符号字符)和位掩码之外的任何内容相结合。)