76

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;
}
4

3 に答える 3

205

コードがまったくコンパイルされるのは、おそらくusing namespace stdどこかにあるためです。(それ以外の場合vectorstd::vector.)それは私が反対することをお勧めします。あなたはその理由を説明しました:
偶然にも、あなたの呼び出しは をピックアップしstd::distance()、2 つの反復子を取り、それらの間の距離を計算します。using ディレクティブを削除し、すべての標準ライブラリ タイプの前に を付けます。コンパイラは、a が必要な場所に astd::を渡そうとしたことを通知します。vector <point>::iteratorpoint*

イテレータが指すオブジェクトへのポインタを取得するには、オブジェクトへの参照を与えるイテレータを逆参照し、結果のアドレスを取得する必要があります: &*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 コンパイラから解析されると問題が発生します (コードはstruct point、単純に ではなく、 thenを参照する必要があります) が、いずれにせよ、C コンパイラにとってはるかに大きな課題になるとpoint思います。std::vector

于 2010-04-26T08:50:52.773 に答える
21

偶然にも、独自の距離関数を呼び出す代わりに、イテレータ間の距離を計算する組み込みの 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) << " ";
于 2010-04-26T08:48:52.657 に答える
6

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

  1. 関数がオブジェクトdistance()を参照するようにしpointます。distance()これは、関数 を呼び出すときに物事を読みやすくするためだけのものです。
    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));
    }
    
  2. オブジェクト distance()を渡すように呼び出すときにイテレータを間接参照します。point
    distance( *ii, *jj)
    
    関数のインターフェースを変更しない場合は、distance()適切なポインターを取得するために、次のようなものを使用して関数を呼び出す必要がある場合があります。
    distance( &*ii, &*jj)
    
于 2010-04-26T08:55:39.737 に答える