2010-04-26 96 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)