2016-10-14 3 views
2

私はイテレータで単純な算術演算を使って、ベクトルを等分に分割するコードを書いています。私は好奇心だイテレータがend()イテレータを過ぎていないかどうかをランタイムチェックすることは可能ですか?

//selectWords is a vector<string> 
//No is an unsigned integer. 

unsigned wordNo = selectWords.size()/No; 
unsigned remainder = selectWords.size()%No; 

for(auto i = 0; i < No; ++i){ 
    unsigned extra = remainder ? 1 : 0; 

    auto b = selectedWords.begin()+(i*wordNo); 
    auto e = selectedWords.begin() + ((i+1)*wordNo) + extra; 

    if(e > selectedWords.end()) throw logic_error("Iterator e in GridList::createGrids goes past the end of selectWords.") //shouldn't happen unless I've made a mistake. 

    ... 
    //do stuff 
    ... 

    if(remainder > 0) --remainder; 

} 

一部がe > selectedWords.end()です:私は、無効なイテレータを終了過去()の作成を意味可能性があります(私はこれが正しいとかなり確信しているが)私のロジックは非常に良いではないかもしれません。 eがすでにend()を過ぎている場合、それは無効な反復子であり、比較演算子が定義された動作を提供するという保証がないかどうかはわかりません。実際、Ben Voigtの投稿でN3337のthis threadと24.2.7の記事を見てみると、iterator算術を使ってpast-the-end()イテレータを作成することは無意味であるか、違法であることは明らかです。それでも、イテレータがend()を過ぎているかどうかをチェックするには、past-the-end()イテレータの操作で定義された動作が必要です。

この比較を行うことが有効でない場合は、別の方法がありますか?コンパイルする前の論理が正しいことを絶対に確かめなければならないのですか?

+1

を、あなたはそれに1を追加します。実装はend()を返すことができます。つまり、iterator> endのテストは常にfalseになります。 – UKMonkey

+1

'((i + 1)* wordNo)+ extra> selectedWords.size()'を代わりにテストすることができます。 – Jarod42

答えて

0

最後のイテレータ(例えば、それをインクリメントする)を過ぎると、未定義の動作が発生します。

定義されていない動作の結果としてしか存在しないものは、明確に定義された動作を持つコードで任意の操作を実行した結果として存在することはできません。論理的には、定義されたテスト方法が必要ないことを意味します。

0

あなたは、単に右端位置を取得するようにコードを修正することができます:あなたの反復子が最後である場合

size_t No = 3; 
std::vector<int> selectWords = {1,2,3,4,5,6,7,8,9,10}; 
size_t wordNo = (selectWords.size() + No - 1)/No; 
size_t remainder = selectWords.size()%No; 

for(size_t i = 0; i < No; ++i){ 
    size_t start_index = i * wordNo; 
    size_t end_index = std::min(selectWords.size(), start_index + wordNo); 
    auto b = selectWords.begin() + start_index; 
    auto e = selectWords.begin() + end_index; 
    for (auto it = b; it != e; ++it) 
     std::cout << *it; 
//.... 
} 

Test it

関連する問題