我本人确信,在我正在研究的项目中,有符号整数在大多数情况下是最佳选择,即使其中包含的值永远不会是负数。 (更简单的反向 for 循环,更少的错误机会等,特别是对于只能保存 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,这真是太棒了!”,还是您会认为这是一个很好的简单解决方案,可以防止错误并提高可读性。或者也许您更愿意看到我们花了(半)天左右的时间来更改所有这些循环以使用 std::vector::iterator?
(特别是如果该解决方案与禁止对除原始数据(例如无符号字符)和位掩码之外的任何内容使用无符号类型相结合。)