0

关于访问最后一项,输入迭代器的行为是否正确:

for(i=being();i!=end();i++){}
std::string s = i->toString();
return s;

或者如果我尝试这样做,它应该抛出异常吗?

我的迭代器使用了两个 c 函数调用:getFirst(...) 和 getNext(...)

4

4 回答 4

2

这不是正确的行为。C++ 中的标准约定是,end()应该指向最后一项之外的位置。取消引用它通常会导致未定义的行为(C++11 §24.2.2/5)。

您可以创建自己的迭代器来原谅取消引用end()并利用它,但它偏离了标准做法,并使人们难以理解您的代码。我建议您抛出异常而不是返回最后一项。


在标准 C++ 中,如果您只有一个不可重现的输入迭代器,那么除非您每次都提取它,否则不可能“获取最后一项”:

auto it = begin();
auto val;
while (it != end()) {
    val = *it;
    ++ it;
}
return val;

但是如果你可以创建一个前向迭代器,那么你可以使用

auto iter = begin();
decltype(iter) last_iter;
while (true) {
    last_iter = iter++;
    if (iter == end())
        break;
}
return last_iter;

或者,如果您创建两次输入迭代器很便宜,您可以进行两次迭代:

auto dist = std::distance(begin(), end());
auto last_iter = begin();
std::advance(last_iter, dist - 1);
return last_iter;
于 2012-07-02T14:09:30.223 回答
0

不,这不行,您将取消引用end()并调用未定义的行为。考虑:

int main()
{
    int i = 0;
    for (; i < 42; ++i) ;
    std::cout << i;    // prints 42, did you expect 41?
}

当然,除非您实现了迭代器类以在这种情况下做一些明智的事情。然而,这对于标准库迭代器来说是不行的。

于 2012-07-02T14:05:59.857 回答
0

该行为是未定义的,在实现迭代器时您无需对其执行任何操作(甚至无需抛出异常)。在实现 InputIterators 时,您只需要实现操作

  • iter == iter2,iter != iter2
  • *iter,iter->...
  • ++iter,(void)iter++
  • *r++

其中,只有最后一个是困难的(您必须从前一个位置返回数据,而迭代器移动到下一个位置)。它通常由记住旧数据的代理实现。

于 2012-07-02T14:25:28.960 回答
0

就 stl 容器而言,这不是正确的行为。

结尾()

返回一个迭代器,该迭代器引用列表容器中的最后一个元素。

这意味着在您的循环之后,i 没有指向正确的对象(不是最后一个元素),而是指向一个特殊定义的结束值,这将导致调用 i->toString() 时发生访问冲突。

于 2012-07-02T14:09:48.560 回答