0

最後の項目へのアクセスに関して、これは入力イテレータの正しい動作ですか?

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

それとも、これを行おうとすると例外をスローする必要がありますか?

私のイテレータは、getFirst(...)とgetNext(...)の2つのc関数呼び出しを使用します。

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;

または、入力イテレータを 2 回作成するのが安価な場合は、反復を 2 回行うことができます。

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

stl コンテナーに関する限り、これは正しい動作ではありません。

終わり()

リスト コンテナー内の末尾要素を参照する反復子を返します。

これは、ループの後、 i が正しいオブジェクト (最後の要素ではない) を指すのではなく、特別に定義された終了値を指すことを意味します。これにより、i->toString() の呼び出し時にアクセス違反が発生します。

于 2012-07-02T14:09:48.560 に答える
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 == iter2iter != iter2
  • *iteriter->...
  • ++iter(void)iter++
  • *r++

それらのうち、最後のものだけが難しいです (反復子が次の位置に移動している間、前の位置からデータを返す必要があります)。通常、古いデータを記憶するプロキシによって実装されます。

于 2012-07-02T14:25:28.960 に答える