C++ 如何使用迭代器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2712076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:27:02  来源:igfitidea点击:

How to use an iterator?

c++pointersvectoriteratorusing-statement

提问by sbi

I'm trying to calculate the distance between two points. The two points I stored in a vector in C++: (0,0) and (1,1).

我正在尝试计算两点之间的距离。我在 C++ 中存储在向量中的两个点:(0,0) 和 (1,1)。

I'm supposed to get results as

我应该得到结果

0
1.4
1.4
0

But the actual result that I got is

但我得到的实际结果是

0
1
-1
0

I think there's something wrong with the way I use iterator in vector. How can I fix this problem?

我认为我在向量中使用迭代器的方式有问题。我该如何解决这个问题?

I posted the code below.

我在下面发布了代码。

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

回答by sbi

That your code compiles at all is probably because you have a using namespace stdsomewhere. (Otherwise vectorwould have to be std::vector.) That's something I would advise againstand you have just provided a good case why:
By accident, your call picks up std::distance(), which takes two iterators and calculates the distance between them. Remove the using directive and prefix all standard library types with std::and the compiler will tell you that you tried to pass a vector <point>::iteratorwhere a point*was required.

你的代码完全编译可能是因为你有一个using namespace std地方。(否则vector必须是std::vector。)这是我建议反对的事情,您刚刚提供了一个很好的案例原因:
偶然地,您的电话会拿起std::distance(),它需要两个迭代器并计算它们之间的距离。删除 using 指令并为所有标准库类型添加前缀std::,编译器会告诉您您试图在需要a 的vector <point>::iterator地方传递 a point*

To get a pointer to an object an iterator points to, you'd have to dereference the iterator - which gives a reference to the object - and take the address of the result: &*ii.
(Note that a pointer would perfectly fulfill all requirements for a std::vectoriterator and some earlier implementations of the standard library indeed used pointers for that, which allowed you to treat std::vectoriterators as pointers. But modern implementations use a special iterator class for that. I suppose the reason is that using a class allows overloading functions for pointers and iterators. Also, using pointers as std::vectoriterators encourages mixing pointers and iterators, which will prevent the code to compile when you change your container.)

要获得指向迭代器指向的对象的指针,您必须取消引用迭代器(它提供对对象的引用)并获取结果的地址:&*ii
(请注意,指针将完全满足std::vector迭代器的所有要求,并且标准库的一些早期实现确实为此使用了指针,这允许您将std::vector迭代器视为指针。但是现代实现为此使用了一个特殊的迭代器类。我想原因是使用类允许为指针和迭代器重载函数。此外,使用指针作为std::vector迭代器会鼓励混合使用指针和迭代器,这将阻止代码在更改容器时编译。)

But rather than doing this, I suggest you change your function so that it takes references instead (see this answerfor why that's a good idea anyway.) :

但与其这样做,我建议您更改您的函数,以便它接受引用(请参阅此答案以了解为什么这是一个好主意。):

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

Note that the points are taken by constreferences. This indicates to the caller that the function won't change the points it is passed.

请注意,这些点是通过const引用获得的。这向调用者表明该函数不会改变它传递的点数。

Then you can call it like this: distance(*ii,*jj).

然后,你可以这样调用:distance(*ii,*jj)



On a side note, this

附带说明一下,这

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

is a C-ism unnecessary in C++. Just spell it

是 C++ 中不必要的 C-ism。拼一下就行

struct point {
    float x;
    float y;
};

That would make problems if this structdefinition ever was to parse from a C compiler (the code would have to refer to struct pointthen, not simply point), but I guess std::vectorand the like would be far more of a challenge to a C compiler anyway.

如果这个struct定义要从 C 编译器解析(代码必须引用struct point那时,而不是简单地point),那会产生问题,但我猜std::vector无论如何对 C 编译器来说都是一个更大的挑战。

回答by Joris Timmermans

By coincidence, you're actually using a built-in STL function "distance", which calculates the distance between iterators, instead of calling your own distance function. You need to "dereference" your iterators to get the contained object.

巧合的是,您实际上使用的是内置的 STL 函数 "distance",它计算迭代器之间的距离,而不是调用您自己的距离函数。您需要“取消引用”您的迭代器以获取包含的对象。

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

As you can see from the syntax above, an "iterator" is quite a lot like a generalized "pointer". The iterator cannot be used as "your" object type directly. In fact iterators are so similar to pointers that many standard algorithms that operate on iterators work fine on pointers as well.

从上面的语法可以看出,“迭代器”很像广义的“指针”。迭代器不能直接用作“您的”对象类型。事实上,迭代器与指针非常相似,以至于许多对迭代器进行操作的标准算法在指针上也能很好地工作。

As Sbi noted: your distance function takes pointers. It would be better rewritten as taking const references instead, which would make the function more "canonical" c++, and make the iterator dereference syntax less painful.

正如 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) << " ";

回答by Michael Burr

You might do a couple of things:

你可能会做几件事:

  1. Make the distance()function take references to pointobjects. This is really just to make things more readable when calling the distance()function:
    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. Dereference your iterators when calling distance()so you're passing the pointobjects:
    distance( *ii, *jj)
    
    If you don't change the interface of the distance()function, you might have to call it using something like the following to get appropriate pointers:
    distance( &*ii, &*jj)
    
  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)