web-dev-qa-db-ja.com

イテレータの使用方法は?

2点間の距離を計算しようとしています。 C++のベクトルに保存した2つのポイント:(0,0)と(1,1)。

結果を取得することになっています

0
1.4
1.4
0

しかし、私が得た実際の結果は

0
1
-1
0

ベクトルでイテレータを使用する方法に何か問題があると思います。この問題を修正するにはどうすればよいですか?

以下のコードを投稿しました。

typedef struct point {
    float x;
    float y;
} point;

float distance(point *p1, point *p2)
{
    return sqrt((p1->x - p2->x)*(p1->x - p2->x) +
                (p1->y - p2->y)*(p1->y - p2->y));
}

int main()
{
    vector <point> po;
    point p1; p1.x = 0; p1.y = 0;
    point p2; p2.x = 1; p2.y = 1;
    po.Push_back(p1);
    po.Push_back(p2);

    vector <point>::iterator ii;
    vector <point>::iterator jj;
    for (ii = po.begin(); ii != po.end(); ii++)
    {
        for (jj = po.begin(); jj != po.end(); jj++)
        {
            cout << distance(ii,jj) << " ";
        }
    }
    return 0;
}
70
user188276

コードがコンパイルされるのは、おそらく_using namespace std_がどこかにあるためです。 (それ以外の場合はvectorは_std::vector_でなければなりません。) それは私が助言することです そしてあなたはただ理由を説明します:
偶然、あなたの呼び出しはstd::distance()をピックアップします。これは2つのイテレータを取り、それらの間の距離を計算します。 usingディレクティブを削除し、すべての標準ライブラリタイプに_std::_をプレフィックスします。コンパイラは、_vector <point>::iterator_が必要な場所に_point*_を渡そうとしたことを通知します。

イテレータが指すオブジェクトへのポインタを取得するには、イテレータを逆参照し(オブジェクトへの参照を提供)、結果のアドレスを取得する必要があります:_&*ii_。
(ポインタは_std::vector_イテレータのすべての要件を完全に満たし、標準ライブラリの以前の実装では実際にポインタを使用していたため、_std::vector_イテレータをポインタとして扱うことができます。しかし、現代の実装ではそのために特別なイテレータクラスを使用します。その理由は、クラスを使用すると、ポインタとイテレータの関数をオーバーロードできるからです。また、ポインタを_std::vector_イテレータとして使用すると、コンテナを変更するときにコンパイルするコード。)

しかし、これを行うのではなく、関数を変更して、代わりに参照を取得することをお勧めします(それがとにかく良いアイデアである理由については、 この回答 を参照してください):

_float distance(const point& p1, const point& p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                (p1.y - p2.y)*(p1.y - p2.y));
}
_

ポイントはconst参照によって取得されることに注意してください。これは、関数が渡されるポイントを変更しないことを呼び出し元に示します。

次に、distance(*ii,*jj)のように呼び出します。


サイドノートでは、これ

_typedef struct point {
    float x;
    float y;
} point;
_

c ++では不要なC-ismです。綴るだけ

_struct point {
    float x;
    float y;
};
_

このstruct定義がCコンパイラから解析する場合(コードは単にpointではなく_struct point_を参照する必要がありますが、_std::vector_などは、とにかくCコンパイラにとってはるかに難しい課題です。

188
sbi

偶然にも、実際には 組み込みSTL関数 "distance" を使用しています。これは、独自の距離関数を呼び出す代わりに、反復子間の距離を計算します。含まれるオブジェクトを取得するには、イテレータを「参照解除」する必要があります。

cout << distance(&(*ii), &(*jj)) << " ";

上記の構文からわかるように、「イテレータ」は一般化された「ポインタ」に非常によく似ています。イテレータを「自分の」オブジェクトタイプとして直接使用することはできません。実際、イテレーターはポインターに非常に似ているため、イテレーターで動作する多くの標準アルゴリズムがポインターでも正常に機能します。

Sbiが指摘したように、距離関数はポインターを受け取ります。代わりにconst参照を使用するように書き直すと、関数がより「標準的な」c ++になり、反復子の逆参照構文の痛みが軽減されます。

float distance(const point& i_p1, const point& i_p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                (p1.y - p2.y)*(p1.y - p2.y));
}

cout << distance(*ii, *jj) << " ";
21

あなたはいくつかのことをするかもしれません:

  1. distance()関数がpointオブジェクトへの参照を取るようにします。これは実際にdistance()関数を呼び出すときに物事をより読みやすくするためです:

    _float distance(point const& p1, point const& p2)
    {
        return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                    (p1.y - p2.y)*(p1.y - p2.y));
    }
    _
  2. distance()を呼び出すときにイテレータを間接参照するため、pointオブジェクトを渡します。

    _distance( *ii, *jj)
    _

distance()関数のインターフェースを変更しない場合、適切なポインターを取得するには、次のようなものを使用して呼び出す必要があります。

_distance( &*ii, &*jj)
_
6
Michael Burr