如何使用迭代器?


72

我正在尝试计算两点之间的距离。我在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;
}

Answers:


194

您的代码完全可以编译,可能是因为您有using namespace std某个地方。(否则vector必须这样做std::vector。)我建议您这样做而您刚刚提供了一个很好的理由:
偶然,您的呼叫接通了std::distance(),这需要两个迭代器并计算它们之间的距离。删除using指令,并为所有标准库类型加上前缀std::,编译器会告诉您您尝试传递需要a的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编译器中解析出来的,那将会带来问题(代码必须struct point然后而不是简单地引用point),但是我想std::vector无论如何,类似的东西对C编译器来说都是更大的挑战。


14
这个答案是不正确的。ADL可以在std ::迭代器上获取std :: distance,因此无论是否std使用它都可能成为候选集的一部分。
小狗

4
@Puppy:的确是这样(并且2.5年来没有人注意到),但这并不是我的全部回答。每个通过点const point& p1也将解决此问题。
sbi 2014年

5
@sbi:不,它不能解决问题。仍然可能会错误地编写distance(ii, jj)和获取std::distance
Ben Voigt,2015年

10
尽管没有人说过,但最明显的方法是强制使用距离版本,它是在编写::distance(...)而不是distance(...)在调用函数时编写的。您的distance函数是在全局名称空间中定义的,因此,您可以使用空前缀限定函数的名称::distance(当然,必须取消引用迭代器才能正确调用它)。
Peregring-lk

4
使用命名空间std; 这是非常糟糕的做法。那就是在这里要考虑的事。
amanuel2 '16

21

碰巧的是,您实际上是在使用内置的STL函数“ distance”,该函数计算迭代器之间的距离,而不是调用您自己的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(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)
    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.