如何使用迭代器?

71 c++ pointers iterator vector using-statement

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

我应该得到结果

0
1.4
1.4
0
Run Code Online (Sandbox Code Playgroud)

但我得到的实际结果是

0
1
-1
0
Run Code Online (Sandbox Code Playgroud)

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

我发布了以下代码.

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;
}
Run Code Online (Sandbox Code Playgroud)

sbi*_*sbi 190

你的代码完全编译可能是因为你有一个using namespace std地方.(否则vector必须是std::vector.)这是我建议反对的,你刚刚提供了一个很好的案例原因:
不小心,你的电话接听std::distance(),需要两个迭代器并计算它们之间的距离.删除using指令与前缀的所有标准库类型std::,编译器会告诉你,你想传递一个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));
}
Run Code Online (Sandbox Code Playgroud)

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

然后你就可以这样称呼:distance(*ii,*jj).


在旁注,这

typedef struct point {
    float x;
    float y;
} point;
Run Code Online (Sandbox Code Playgroud)

在C++中是不必要的C-ism.拼这个吧

struct point {
    float x;
    float y;
};
Run Code Online (Sandbox Code Playgroud)

如果这个struct定义是从C编译器解析的话会产生问题(代码必须引用struct point当时的,而不是简单的point),但我猜想std::vector等等对C编译器来说更是一个挑战.

  • 这个答案是不正确的.std :: distance可以在std :: iterator上由ADL拾取,因此无论是否使用`std`,它都可以构成候选集的一部分. (12认同)
  • 虽然没有人这样做,但是,当你调用函数时,最明显的强制你的版本距离的方法就是写`:: distance(...)`而不是`distance(...)`.你的`distance`函数是在全局命名空间中定义的,因此,你可以使用空前缀`:: distance`来限定函数的名称(当然,你必须取消引用迭代器才能正确调用它). (9认同)
  • @sbi:不,它不会解决问题.仍然可能错误地写出'distance(ii,jj)`并获得`std :: distance`. (5认同)
  • @Puppy:确实如此(2.5年没有人注意到),但这不是我的回答.每个'const point&p1`传递点也可以解决这个问题. (3认同)
  • using namespace std; 是一个非常糟糕的做法..这就是在这里想到的......传播这个词! (3认同)

Jor*_*ans 21

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

cout << distance(&(*ii), &(*jj)) << " ";
Run Code Online (Sandbox Code Playgroud)

从上面的语法中可以看出,"迭代器"与广义的"指针"非常相似.迭代器不能直接用作"您的"对象类型.事实上,迭代器与指针非常相似,因此许多在迭代器上运行的标准算法也可以在指针上正常工作.

正如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) << " ";
Run Code Online (Sandbox Code Playgroud)


Mic*_*urr 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));
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在调用时取消引用迭代器,distance()以便传递point对象:

    distance( *ii, *jj)
    
    Run Code Online (Sandbox Code Playgroud)

如果不更改distance()函数的接口,则可能必须使用以下内容调用它以获取适当的指针:

distance( &*ii, &*jj)
Run Code Online (Sandbox Code Playgroud)