2012-07-02 175 views
0

是对输入迭代器这个正确的行为,关于访问的最后一个项目:得到最后一个项目

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

还是应该抛出一个异常,如果我尝试这样做?

我的迭代器利用了两个C函数调用:getFirst(...)和GetNext(...)

+0

这应该工作,除了你拼写'开始'错误。 – Daniel

+1

@RedX,Daniel:这是错误的,'i == end()'在循环结束后。 – kennytm

+0

@血液我正在移动到最后,然后访问最后一个项目。由于迭代器只有函数的第一个和下一个我不能跳到最后一步 – Baz

回答

0

不,这也不行,你会被提领end()和调用未定义的行为。考虑:

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

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

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; 
+1

+1今天所有的upvoters在哪里? :P – jrok

0

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

端()

返回一个迭代参照过去最端部元件在列表 容器。

这意味着你的循环后,我不指向一个正确的对象(而不是最后一个元素),而是指向一个特殊的定义的最终值,这将导致访问冲突调用i->的toString()。

+0

我不明白。我的代码中执行了i = end()吗?仅仅因为i == end()是真的并不意味着end() - > toString()和i-> toString()是相同的东西,还是? – Baz

+2

@Baz是的,实际上它是一样的。你还认为这种情况会是真的吗? – jrok

+1

@Baz,如果你写'int j = 3; j ++;',那么你实际上没有*写* * j = 4,然而'j'已经获得了4的值。同样,分配一个迭代器并且递增它最终将导致它获得该序列中的最后一个迭代器,也称为'end'。 –

0

行为是未定义的,在实现迭代器时无需做任何事情(甚至不需要引发异常)。在实施InputIterators,你只需要执行的操作

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

其中,只有最后一个是很难(当你将迭代器移到时,你必须返回前一个位置的数据下一个)。它通常由一个代理来实现,它记住了旧数据。