2012-07-02 90 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++

其中,只有最後一個是很難(當你將迭代器移到時,你必須返回前一個位置的數據下一個)。它通常由一個代理來實現,它記住了舊數據。