我会实现一个函数,访问给定元素的相邻元素。
这是一个简单的例子:对距离一维数组中给定元素的半径距离内的元素求和。 C代码是:
int sum(int *elem_ptr, int radius) {
int sum = 0;
for (int *ptr = elem_ptr - radius; ptr <= elem_ptr + radius; ptr++) {
sum += *ptr;
}
return sum;
}
但是,上面的代码没有检查ptr用完数组边界的情况。所以,我想自动提供这种边界检查功能。换句话说,我们不需要将边界检查代码添加到上面的代码中。
我正在考虑使用C ++运算符重载,它允许'*'运算符检查边界。但是,我不知道该怎么做。
答案 0 :(得分:1)
在C ++中,在容器上使用迭代器是可行的方法,而不是像代码示例中所示进行指针运算。 迭代器也比原始索引更好,因为它使您的代码与任何容器兼容(例如,集合或映射没有索引)。
使用最近的STL,可用于操作迭代器的工具包已变得非常通用:
std::prev(iterator, n)
移动迭代器n向后排列 (向集合的开头)(ref) std::next(iterator, n)
移动前进 (ref) std::distance(a, b)
计算迭代器之间的元素数量,这对于检查您是否超出范围非常有用(ref) 使用迭代器还会产生另一个好的副作用:您将能够使用标准库中已有的众多算法之一,例如来自<algorithm>
或<numeric>
。
事实证明,有一个函数已经计算了一系列元素的总和:std::accumulate
。您需要做的就是根据您的需要(ref. on accumulate)使用它。
这是一个不完美的实现的开始,但大部分时间都应该可以。
#include <functional>
#include <numeric>
int sum(const std::vector<int>& v,
const std::vector<int>::const_iterator elem,
size_t radius)
{
auto first_radius = (std::abs(std::distance(std::cbegin(v), elem)) < radius)
? std::cbegin(v)
: std::prev(elem, radius);
auto last_radius = (std::abs(std::distance(elem, std::cend(v))) < radius)
? std::cend(v)
: std::prev(elem, radius);
return std::accumulate(first_radius, last_radius, 0, std::plus<int>());
}
如果您不习惯语法,这似乎有点压倒性,但大部分都是绑定检查。 first_radius
和last_radius
是你“mask”半径的边界的迭代器,确保它们不在向量的“外部”(请注意,我不确定此代码是100%的bug-自由)。之后,让std::accumulate
为我们做繁重的工作!
您可以使用以下代码:
std::vector<int> x = { 0, 1, 0, 1, 0, 1};
const int a = sum(x, std::next(std::cbegin(x), 3), 15);
const int b = sum(x, std::prev(std::cend(x), 1), 2);
根据您对语言的熟悉程度,可能会有很多信息。值得花些时间查看我在这里使用的函数的文档,因为它实际上是惯用的方法(对于C ++,请注意)。
作为结束语:您必须注意到我在我的示例中使用了std::vector
。好吧,迭代器很好用:我们可以使这个函数完全与容器无关!
使用模板,它可以用于地图,数组,集合,自定义容器...您可以命名。但这次应该足够了......如果你有兴趣的话,不要介意问我这个模板技巧。
玩得开心!
答案 1 :(得分:0)
由于数组很痛苦,我将首先使用std::vector
提供解决方案。
int sum_vector_neighbor(const std::vector<int>& values,
unsigned int position, // negative positions are weird.
unsigned int radius) // negative radii are weird.
{
if (values.empty())
{
return 0;
}
const unsigned int size = values.length();
unsigned int start_index = 0U;
unsigned int end_index = size - 1;
if (radius < position)
{
start_index = position - radius;
}
if ((position + radius) < size)
{
end_index = position + radius;
}
sum = 0;
for (; start_index < end_index; ++start_index)
{
sum += values[start_index];
}
return sum;
}
上面的解决方案是使用索引而不是指针,因为索引比指针更容易比较。
使用索引的习惯用法可以应用于数组。对于阵列版本,您需要另外传递数组的容量,因为当数组转换为指向第一个元素的指针时,capacity属性将被删除。
我不建议使用指针,因为你必须从指针中减去半径值(这是一个有效的操作),但是比较小于或大于不是所有平台支持的操作< / em>的。