2010-04-26 112 views
61

我在計算兩點之間的距離。我用C++存儲在矢量中的兩點:(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; 
} 

回答

158

你的代碼編譯完全可能是因爲你有一個using namespace std的地方。 (否則vector將必須是std::vector。)That's something I would advise against並且您剛剛提供了一個很好的理由:
意外,您的呼叫接收std::distance(),它需要兩個迭代器並計算它們之間的距離。刪除使用指令並用std::前綴所有標準庫類型,編譯器會告訴您,您嘗試通過vector <point>::iterator,其中需要point*

要獲取指向迭代器指向的對象的指針,您必須對引用該對象的迭代器進行取消引用,並獲取結果的地址:&*ii。 (請注意,指針可以很好地滿足迭代器的所有要求,標準庫的一些早期實現確實使用了指針,這使得您可以將std::vector迭代器當作指針使用,但現代實現使用特殊的迭代器類來實現。我想這是因爲使用類允許重載指針和迭代器的函數。另外,使用指針作爲std::vector迭代器會鼓勵混合指針和迭代器,這會在更改容器時阻止編譯代碼。)

但而不是這樣做,我建議你改變你的功能,以便它取而代之(參見this answer爲什麼這是一個好主意)。:

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++中不必要的。只是拼

struct point { 
    float x; 
    float y; 
}; 

如果這struct定義曾是從C編譯器來解析(代碼將要參考struct point話,不是簡單地point)這將使問題,但我想std::vector之類會無論如何,對C編譯器來說更是一個挑戰。

+10

這個答案不正確。 std :: distance可以由ADL在std :: iterator中拾取,因此無論是否使用'std',它都可以形成候選集的一部分。 – Puppy 2014-09-13 17:18:29

+2

@Puppy:確實如此(2.5年來沒有人注意到),但這並不是我所有的答案。通過'const point&p1'傳遞點也可以解決這個問題。 – sbi 2014-10-13 16:45:18

+3

@sbi:不,它不會解決問題。仍然有可能錯誤地寫'distance(ii,jj)'並且得到'std :: distance'。 – 2015-05-09 23:10:19

17

巧合的是,你實際上使用a built-in STL function "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) << " "; 
6

你可能會做兩件事情:

  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)