我正在为一个基于索引的类实现一个迭代器。有一个最大有效值;我的问题是当客户端代码将迭代器推进到我的end()
值以外时该怎么做:
operator++()
是否应始终检查我是否已经过了结束?或operator*()
是否应该始终检查我是不是已经过了结束,而迭代器可以(无用地)提前或移动到最后?请解决一个非调试设置,我无法确定愚蠢的开发人员是否会尝试在结束之前推进他们的指针。
答案 0 :(得分:5)
这并不重要。
要符合STL约定,您需要一个begin()方法,它返回一个迭代器到集合的开头,以及一个end()方法,它将迭代器返回到最后一个元素之后。所以推进到end()和比较相等是明确的。然而,超越end()的进展并没有明确定义。最好抛出错误,但不是必需的,特别是如果涉及其他冗余检查。如果人们没有正确使用迭代器,则不对任何错误负责。
答案 1 :(得分:0)
我所做的是在编译调试版本时添加严格的检查代码,并删除对代码发布版本的检查。
我广泛使用assert
(或类似)。除非使用定义的宏NDBUG
进行编译,否则它将执行运行时检查,在这种情况下,检查将完全消除。
STL理念本身应提供一种安全措施,即迭代器限制通常来自安全的地方。
运行算法时,通常会从这样的容器中获取边界:
std::vector<int> v {1, 2, 3, 4};
do_some_stuff(std::begin(v), std::end(v));
否则,您可能会因算法而获得迭代器:
auto found_iter = std::find(std::begin(v), std::end(v));
这使得使用迭代器非常安全。当你开始使用iterator athematic时,它会有点危险:
auto dangerous_iter = std::begin(v) + 5; // not encouraged
但是在调试阶段应该使用assert
和类似的错误来捕获错误。
要记住的另一点是,如果通过运行时检查使迭代器“安全”,则最终可能会在代码中隐藏错误。因为这样的运行时检查应该引起像异常一样的可见景象,所以不要只是默默地做什么。
答案 2 :(得分:-2)
基于@ MalcolmMclean的回答:由于C ++标准在移动到范围的末尾时没有定义迭代器的行为,所以确保它不会这样做是客户端代码的问题 - 而不是你的。所以当你没有调试时,不要因为范围检查而牺牲性能,只要假设你没有超越结束。
当 编译进行调试时,正如@ Phil1970建议的那样,使用异常抛出或使用断言进行范围检查可能是一个好主意。