在c ++ 11中,最现代的方式是迭代向量的最“正确”方式

时间:2014-07-25 09:47:55

标签: c++ vector

我现在正在学习C ++,而且我看到很多方法来迭代一个向量。 我想知道,因为我想以正确的方式学习它,现在最正确的迭代方法是什么?

6 个答案:

答案 0 :(得分:3)

取决于以下因素:

  1. 您是否需要循环内的迭代器或仅需要元素?
  2. 您更喜欢几乎始终自动(AAA)或几乎从不自动(ANA)?
  3. 例如,如果您只想循环std::vector<int> v元素的某些副本,则可以执行以下操作:

    for (int element : v) {
       // Use element
    }
    

    如果你是AAA人,你可以改为auto element

    如果你想避免复制,你需要一个const引用:

    for (int const &element : v) {
      // Use element
    }
    

    如果你是AAA人,你可以改为auto const &element

    如果要修改向量内的值,则需要可修改的引用:

    for (int &element : v) {
      // Use element
    }
    

    再一次,如果您喜欢AAA,那么请改为auto &element

    如果你需要循环中的迭代器:

    for (std::vector<int>::iterator it = std::begin(v); it != std::end(v); ++it) {
      // Use it
    }
    

    如果你是AAA人:

    for (auto it = std::begin(v); it != std::end(v); ++it) {
      // Use it
    }
    

    请注意,如果循环中的代码不依赖于实际类型(这不是很常见),ANA人员也会使用auto

    另请注意,您通常可以使用<algorithm>中的相应算法完全避免循环。查看Sean Parent's talk以获取有关此内容的一些信息。他认为任何包含多行的循环都是不好的,通常可以写得更整齐。

答案 1 :(得分:2)

对于所有情境都没有正确的方法。最简单的是for循环:

std::vector<SomeClass> v;
for (SomeClass& sc : v)
   sc.Method();

但在某些情况下,std::for_each可能更好,甚至可能更好for(;;)

答案 2 :(得分:2)

使用Iterators ...它们是专门为此目的而设计的,适用于所有STL数据结构

http://www.cplusplus.com/reference/vector/vector/begin/

^链接将有助于理解示例

答案 3 :(得分:0)

迭代向量的方式取决于迭代的目的。示例如下。

标准库算法

如果您的目的存在标准库算法,请使用它。当操作可以简单地使用lambda,函数或仿函数表示时,这包括搜索,累积,转换等。它还允许您通过提供适当的迭代器来迭代您选择的范围,即不只是beginend

示例:计算向量的前20个元素的总和

std::vector<int> v = { /* fill as appropriate */ };
int sum_20 = std::accumulate(std::begin(v), std::begin(v)+20, 0);

示例:将每个元素加倍并存储在另一个向量

std::vector<int> v = { /* fill as appropriate */ };
std::vector<int> doubled;
doubled.reserve(v.size()); // avoid reallocations
std::transform(std::begin(v), std::end(v), 
               std::back_inserter(doubled), [](int x){return x*2;})

基于范围的

示例:

std::vector<int> v = { /* fill as appropriate */ };
for (int& x : v)
{
    do_something_with(x);
    do_another_thing_with(x);
    if (some_condition(x))
    {
        do_something_else();
    }
}

这适用于遍历整个容器,其中您想要执行的操作比您想要在一个普通的lambda中表示的更复杂,但不够大(或使用)不止一次)证明自己的功能。

您还可以在一定程度上自定义访问元素的方式。如果元素很大,而您只是阅读它们,则可以指定const foo&

for (const MyBigObject& : MyBigContainer) { /* ... */ }

如果您需要修改它们,请删除const:

for (MyBigObject& : MyBigContainer) { /* ... */ }

对于小物件或需要副本的地方,请删除参考:

for (int x : MyVecInt) { /* ... */ }

这允许您为访问指定最合适的常量,并控制您是通过引用还是值访问。类似的事情可以通过提供const或非const迭代器与标准库算法一起完成,并结合适当的参数类型,用于提供给采用可调用实体的算法的任何函数/ functor / lambda。

请注意,基于范围的for只会迭代整个容器,并且没有简单的方法可以同时迭代两个或多个容器。与...相比,这限制了它的适用性。

常规

如果需要同时迭代多个容器,或者需要访问索引或迭代器以及元素本身,那么常规for循环可能是正确的方法。这是最灵活的,允许您自定义迭代的每个方面,但它不会利用任何标准的库优化,并且通常需要更多样板来设置迭代器/索引对,检查您是否'在容器的范围内等等。

示例:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {2, 4, 6};
for (std::vector<int>::size_type idx = 0; idx < v1.size(); ++idx)
{
    std::cout << v1[idx] * v2[idx] << ", ";
}

std::vector<int> v1 = {1, 2, 3};
auto iter = v1.cbegin();
const auto end = v1.cend() - 1;
for (; iter != end; ++iter)
{

    std::cout << *iter + *(iter+1) << "\n";
}

答案 4 :(得分:0)

这取决于你为什么要重复。在许多情况下,根本不应该迭代;使用标准算法之一。否则,如果要访问仅一个容器的所有元素,则范围for是最佳解决方案。如果您可能希望尽早中断迭代,那么更喜欢正常的for,除非(通常情况下)您需要循环后的迭代器,在这种情况下while可能会更好;在这两种情况下,使用迭代器。最后,如果你并行地迭代几个向量,那么使用一个索引而不是几个迭代器可能更清楚。

总之,这就是为什么你有这么多选择的原因。

答案 5 :(得分:0)

我强烈建议使用range-for循环(自C ++ 11开始)

vector<int> myVector {0, 1, 2, 3, 4};
for (const auto& i : myVector)
  cout << i << endl;

预C ++ 11:

std::for_each(myVector.begin(), myVector.end(), myCallable);

C ++ 14不会添加任何有关此场景的内容;可能是C ++ 17,并行循环。

如果您需要使用索引,可以选择“原始”作为

for (auto i = 0; i < myVector.size(); ++i)

这些是最常见的方式。如果您需要更专业的东西,例如排序,移动,查找,请查看<algorithm>