5

我有一个向量声明为

std::vector<int> MyVector;
MyVector.push_back(5);
MyVector.push_back(6);
MyVector.push_back(7);

我应该如何在 for 循环中使用它?

通过使用迭代器对其进行迭代?

for (std::vector<int>::iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
    std::cout << "Vector element (*it): " << *it << std::endl;
}

还是通过它的访问迭代器?

for (std::vector<int>::size_type i=0; i<MyVector.size(); i++)
{
    std::cout << "Vector element  (i) : " << MyVector.at(i) << std::endl;
}

在我在互联网上找到的示例中,它们都被使用。在所有条件下,其中一个是否优于另一个?如果不是,我什么时候应该更喜欢其中一个而不是另一个?

4

4 回答 4

5

第一种格式是用于迭代标准库容器的更通用格式,因此更常见和直观。如果您需要更改容器,则此迭代代码不会受到影响。它将适用于每种标准库容器类型,因此它为您提供更通用的代码。

在第二种格式中,std::vector::at()每次迭代时都会检查边界,因此它可能对性能有点不利。第一种格式中不存在此开销,因为不涉及边界检查。请注意,使用的情况也是如此operator[]
请注意,除非您处理大量数据,否则性能滞后并没有您注意到的那么多。

于 2012-09-24T07:47:33.533 回答
3

使用std::vector's [] operator可能更快,因为std::vector::at()在 for 循环中使用会检查向量的大小两次(在 for 循环和 std::vector::at() 的边界检查中)。

第一种方法可以在其他容器中使用,因此可以在您更改容器类型时为您提供很大帮助。

如果您使用 C++11,请使用基于范围的循环。

于 2012-09-24T07:51:50.090 回答
2

首先,如果您有 C++11,请使用基于范围的:

for (auto i : MyVector)
{
    std::cout << i;
}

或者BOOST_FOREACH在 C++03 中:

BOOST_FOREACH(int& i, MyVector)
{
  std::cout << i;
}

或者std::copy

std::copy(MyVector.begin(),
          MyVector.end(), 
          std::ostream_iterator<int>(std::cout, "\n"));

至于手头的问题,at()检查索引是否在界限内,如果不在则抛出异常。所以,除非你需要额外的检查,否则不要使用它。您拥有它的第一种方式是标准的并且效果很好。有些人很迂腐,甚至是这样写的:

for (std::vector<int>::iterator it=MyVector.begin(), end = MyVector.end(); it!= end; ++it)
{
    std::cout << "Vector element (*it): " << *it << std::endl;
}

在上面我缓存了end迭代器而不是调用end()每个循环。这是否真的会产生性能差异,我不知道。

于 2012-09-24T07:55:51.647 回答
1

没有“一个优于另一个”(除了你几乎不想使用at()-at()只有当你真的可以做一些事情来从错误中恢复时才合适)。迭代器与索引的使用主要是一种风格,以及您传递的信息。更惯用的 C++ 做事方式是迭代器,但来自其他背景的人(例如,数学家)会发现索引更惯用。

有一个真正的区别:

  • 迭代器习语将适用于其他类型的容器。如果您确实有可能使用其他容器,这可能是相关的。

  • 索引习惯用法可以为多个不同的容器使用单个索引。如果您要遍历多个vector具有相同大小的元素,使用索引习惯用法可以更清楚地表明您正在访问每个vector. (同样,这似乎最常发生在数学应用中。)

  • 最后,任何时候你真的在做随机访问,或者以任何方式计算元素,使用索引可能更直观。(在这种情况下,您可能希望在 中进行计算int,仅size_t在最后一刻转换为。)

于 2012-09-24T08:53:19.297 回答