【发布时间】:2023-03-30 14:15:01
【问题描述】:
我正在创建一个基于图块的小游戏。游戏中的项目将它们的位置存储在一个桶矩阵中。我已经将它实现为一个名为 Grid 的类模板,其中包含一个名为 Tile 的存储桶类。
Grid 本质上只是std::vector 的一个包装器,带有用于将坐标转换为索引键的各种访问器方法。它还转发向量的迭代器,以便我可以遍历 Grid 中的所有 Tiles。
虽然有时我只需要遍历Grid 的一个小节。所以我实现了一个名为Section 的小类,它在构造函数中使用两组坐标来定义一个AABB。 Section 的 begin() 和 end() 方法返回输入/输出迭代器,用于循环遍历 AABB 内的所有图块。
一切正常,但我试图使迭代器的性能尽可能接近嵌套循环。基本上使用基于Section 的范围不应该比:
for (size_t y = 0, end_y = NUM; y < end_y; ++y)
{
for (size_t x = 0, end_x = NUM; x < end_x; ++x)
{
auto& tile = grid[coords_to_key(x, y)];
}
}
这让我想到了问题的重点。我希望不等式运算符尽可能简单,所以我这样实现它:
bool operator!=(const Section_Iterator& other) const
{
return m_coords.y < other.m_coords.y;
}
由于迭代器按顺序扫描Section 中的每一行,我们知道当iterator.y >= end.y 时我们已经“结束”了。这意味着我的不等式运算符适用于基于范围的 for 循环,因为在后台他们只是检查 iterator != end。
虽然操作符的实现看起来很奇怪。就像真的很奇怪。例如iterator != ++iterator 可能是真或假。这取决于预增量是否导致迭代器跳转到下一行。
我一直在研究标准,我认为我很清楚,因为它们区分了平等和等价。
来自http://en.cppreference.com/w/cpp/concept/InputIterator
注意,“在 == 的域中意味着相等比较是在两个迭代器值之间定义的。对于输入迭代器,不需要对所有值都定义相等比较,== 域中的值集合可能会随时间变化。
来自http://en.cppreference.com/w/cpp/concept/OutputIterator
不能为输出迭代器定义等式和不等式。即使定义了 operator==,x == y 也不必暗示 ++x == ++y。
不过,老实说,标准语让我头晕目眩。我做的事合法吗?
【问题讨论】:
-
我认为您过早地进行了优化,应该使用最简单的实现来保留
!=运算符的预期语义并且不会让您头疼 -
这是最简单的实现。它只是不一定是 正确的 实现。我试图找出标准中关于输入/输出迭代器的
!=运算符的正确语义是什么,因为它不太清楚。 -
我的意思是,为什么不只是
return m_coords.y != other.m_coords.y;?如果您甚至没有证明它是性能瓶颈,为什么还要让它复杂化呢? -
因为它不适用于浮点坐标。
-
我不确定我是否理解。该部分包含最小和最大浮点坐标。迭代器递增一组浮点坐标,然后在取消引用迭代器时将其转换为向量的索引。我不能只使用向量迭代器,因为瓦片都存储在同一个向量中,一行接一行。部分迭代器必须评估它是否已到达部分行的末尾,跳过网格行中的其余图块,然后找到下一个部分行的开始。如果有帮助,我可以将预增量运算符编辑到问题中。
标签: c++ iterator equality equivalence