1

かなり複雑なデータ構造を持つ、オブジェクトの配列に対してネストされたループを構築したいと考えています。私は配列を使用しているので、そのイテレータを利用したいと考えています。予期しない結果が得られた後、問題を次のコード スニペットに要約しました。これは、イテレータが異なると予想される場合にイテレータが等しいことを示しています。

vector<int> intVecA;
vector<int> intVecB;

intVecA.push_back(1);
intVecA.push_back(2);

intVecB.push_back(5);
intVecB.push_back(4);

Foo fooOne(intVecA);
Foo fooTwo(intVecB);

vector<int>::const_iterator itA = fooOne.getMyIntVec().begin();
vector<int>::const_iterator itB = fooTwo.getMyIntVec().begin();
cout << "The beginnings of the vectors are different: "
     << (fooOne.getMyIntVec().begin() == fooTwo.getMyIntVec().begin()) << endl;
cout << (*(fooOne.getMyIntVec().begin()) == *(fooTwo.getMyIntVec().begin())) << endl;
cout << (&(*(fooOne.getMyIntVec().begin())) == &(*(fooTwo.getMyIntVec().begin()))) << endl;
cout << "But the iterators are equal: "
     << (itA==itB) << endl;

これにより、次が生成されます。

The beginnings of the vectors are different: 0
0
0
But the iterators are equal: 1

この動作は私には意味がありません。説明を聞いていただければ幸いです。

Foo は、ベクターとそのためのゲッター関数を含む単純なオブジェクトです。

class Foo {
    public:
    Foo(std::vector<int> myIntVec);

    std::vector<int> getMyIntVec() const {
    return _myIntVec;
    }

    private:
    std::vector<int> _myIntVec;
};

Foo::Foo(std::vector<int> myIntVec) {
    _myIntVec = myIntVec;
}

最初にベクトルをコピーすると、問題はなくなります。なんで?

vector<int> intVecReceiveA = fooOne.getMyIntVec();
vector<int> intVecReceiveB = fooTwo.getMyIntVec();

vector<int>::const_iterator newItA = intVecReceiveA.begin();
vector<int>::const_iterator newItB = intVecReceiveB.begin();

cout << "The beginnings of the vectors are different: "
     << (intVecReceiveA.begin() == intVecReceiveB.begin()) << endl;
cout << "And now also the iterators are different: "
     << (newItA==newItB) << endl;

生成:

The beginnings of the vectors are different: 0
And now also the iterators are different: 0

詳細なメモ: 計算時間に関して非常に効率的である必要がある関数でこれらのネストされたループが必要なため、不要な操作を実行したくありません。私はc ++を初めて使用するので、ベクターのコピーに実際に時間がかかるのか、それとも内部的にコピーされるのかはわかりません。また、その他のアドバイスもよろしくお願いします。

4

4 に答える 4

2

問題は、Foo のアクセサー:

std::vector<int> getMyIntVec() const {
return _myIntVec;
}

_myIntVec を返しません。myIntVec のコピーを返します。代わりに、次のようになります。

const std::vector<int>& getMyIntVec() const {
return _myIntVec;
}

それ以外の場合、反復子を作成すると、直接破棄されるコピーから作成されるため、C++ コンパイラはアドレスを再利用します。それが、「等しい」イテレータを取得する理由です。少なくともそう思います。

于 2013-04-19T09:07:05.143 に答える
0

ここに深刻な論理上の問題があります。

cout << "The beginnings of the vectors are different: "
 << (fooOne.getMyIntVec().begin() == fooTwo.getMyIntVec().begin()) << endl;

それらが等しい場合、通常期待される 0 ではなく 1 が出力されます。

于 2013-04-19T09:39:48.080 に答える
0

物事を間違った方法で比較していることに気付きましたか? 比べれa == bば、書いても

cout << "a is different from b: " << (a==b) << endl;

出力は、2 つの要素が同じであるかどうかを示します。2 つのものが異なるかどうかを調べる!=には、 の代わりに==.

于 2013-04-19T09:01:00.457 に答える
0

これは、異なるコンテナー内の要素を参照する 2 つの反復子を比較する動作が未定義であるためです。ですので、必ずもらえるという保証はありません。getMyIntVecこれは、 が のコピーを返し、_MyIntVecこれらのコピーを の新しいインスタンスに割り当てるという事実に由来するvector<int>ため、これらは実際にはメンバーの 2 つの異なるコピーの反復子です_MyIntVec

標準によると:

§ 24.2.1

反復子 j は、i == j になる式 ++i の適用の有限シーケンスがある場合にのみ、反復子 i から到達可能であると呼ばれます。j が i から到達可能な場合、それらは同じシーケンスの要素を参照します。

そして少し後の標準:

§ 24.2.5

前方反復子の == のドメインは、同じ基本シーケンスに対する反復子のドメインです。

これは、この質問ですでに回答されています

于 2013-04-19T09:07:59.420 に答える