最後の項目へのアクセスに関して、これは入力イテレータの正しい動作ですか?
for(i=being();i!=end();i++){}
std::string s = i->toString();
return s;
それとも、これを行おうとすると例外をスローする必要がありますか?
私のイテレータは、getFirst(...)とgetNext(...)の2つのc関数呼び出しを使用します。
最後の項目へのアクセスに関して、これは入力イテレータの正しい動作ですか?
for(i=being();i!=end();i++){}
std::string s = i->toString();
return s;
それとも、これを行おうとすると例外をスローする必要がありますか?
私のイテレータは、getFirst(...)とgetNext(...)の2つのc関数呼び出しを使用します。
これは正しい動作ではありません。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;
または、入力イテレータを 2 回作成するのが安価な場合は、反復を 2 回行うことができます。
auto dist = std::distance(begin(), end());
auto last_iter = begin();
std::advance(last_iter, dist - 1);
return last_iter;
stl コンテナーに関する限り、これは正しい動作ではありません。
終わり()
リスト コンテナー内の末尾要素を参照する反復子を返します。
これは、ループの後、 i が正しいオブジェクト (最後の要素ではない) を指すのではなく、特別に定義された終了値を指すことを意味します。これにより、i->toString() の呼び出し時にアクセス違反が発生します。
いいえ、これは問題です。逆参照end()
して未定義の動作を呼び出すことになります。検討:
int main()
{
int i = 0;
for (; i < 42; ++i) ;
std::cout << i; // prints 42, did you expect 41?
}
もちろん、この場合、何か賢明なことを行うためにイテレータ クラスを実装した場合を除きます。ただし、これは標準ライブラリの反復子には適していません。
動作は未定義であり、イテレータの実装中に何もする必要はありません (例外をスローする必要さえありません)。InputIterators を実装するときは、操作を実装するだけで済みます
iter == iter2
、iter != iter2
*iter
、iter->...
++iter
、(void)iter++
*r++
それらのうち、最後のものだけが難しいです (反復子が次の位置に移動している間、前の位置からデータを返す必要があります)。通常、古いデータを記憶するプロキシによって実装されます。