【问题标题】:C++ STL Vectors: Get iterator from index?C ++ STD向量:从索引获取迭代器?
【发布时间】:2010-10-14 20:37:45
【问题描述】:

所以,我写了一堆代码,通过 index[] 访问 stl 向量中的元素,但现在我只需要复制向量的一部分。看起来vector.insert(pos, first, last) 是我想要的功能......除了我只有第一个和最后一个整数。有什么好方法可以让我获得这些值的迭代器吗?

【问题讨论】:

  • 如果我没记错的话,没有一个答案会做任何边界检查,这可能是个问题。具体来说,std::advance 文档说如果您使用它来越过底层容器边界,则该行为是未定义的。

标签: c++ stl vector iterator


【解决方案1】:

试试这个:

vector<Type>::iterator nth = v.begin() + index;

【讨论】:

  • 通常,您可以对 STL 迭代器使用与指针相同的算法。它们被设计为在使用 STL 算法时可交换。
  • @VincentRobert:反过来。指针是 STL 随机迭代器的有效实现,这是最强大的类别。但其他功能较弱的类别(例如前向迭代器)不支持相同的算法。
  • 我想在这个答案上加五分钱,并推荐std::next(v.begin(), index)
【解决方案2】:

@dirkgently ( v.begin() + index ) 提到的方式对向量来说既好又快

但是std::advance( v.begin(), index ) 最通用的方式和随机访问迭代器的工作时间也是恒定的。

编辑
用法差异:

std::vector<>::iterator it = ( v.begin() + index );

std::vector<>::iterator it = v.begin();
std::advance( it, index );

在@litb 注释之后添加。

【讨论】:

  • std::advance 不需要非常量迭代器作为第一个参数吗?
  • 您可以将 std::advance 与 const 和非 const 迭代器一起使用
  • 在这方面你不应该相信 msvc。它有一个非标准的扩展,使它接受这种东西,但是所有其他编译器都表现标准并拒绝它。
  • 我认为问题在于混淆了“const”的含义:advance() 很乐意在 const_iterator 上工作,它是一个可变迭代器,它引用类型 T 的 const 元素;它不适用于本身为 const 的迭代器对象(即“const iterator”或“iterator const”)。
  • 如果你知道你正在处理一个std::vector,那么使用std::advance是没有意义的。它只会诱使您认为您正在编写与容器无关的代码(您不会,考虑到迭代器无效规则、不同的运行时复杂性等等)。 std::advance 有意义的唯一情况是当您自己编写一个模板时,它不知道它正在处理哪种迭代器。
【解决方案3】:

还有; auto it = std::next(v.begin(), index);

更新:需要兼容 C++11x 的编译器

【讨论】:

  • 需要注意的是,这是C++11的方式! std::next 等价于 std::advance。使用这些函数而不是使用算术可以更容易地交换容器类型。甚至适用于 c 数组 afaik,就像 std::begin 和 std::end 一样。
  • for( auto it=begin(c); it != end(c); advance(it, n) ) { ... }
  • std::list lst;迭代器 Fifth_element = *std::next(lst.begin(), 5);
  • 两者各有所用。 stda::advance 对于更改迭代器很有用。这是循环中的性能问题。正如你所建议的,在分配的情况下,我更喜欢下一个。我只是觉得声称它是白痴有点苛刻。这两个功能的设计考虑了不同的情况,尽管它们基本相同。
  • @Zoomulator:如果复制您的迭代器是性能问题,那么您需要处理更大的问题。
【解决方案4】:

或者你可以使用std::advance

vector<int>::iterator i = L.begin();
advance(i, 2);

【讨论】:

    【解决方案5】:

    实际上 std::vector 在需要时用作 C 选项卡。 (据我所知,C++ 标准要求矢量实现 - replacement for array in Wikipedia) 例如,根据我的说法,这样做是完全合法的:

    int main()
    {
    
    void foo(const char *);
    
    sdt::vector<char> vec;
    vec.push_back('h');
    vec.push_back('e');
    vec.push_back('l');
    vec.push_back('l');
    vec.push_back('o');
    vec.push_back('/0');
    
    foo(&vec[0]);
    }
    

    当然,要么 foo 不能复制作为参数传递的地址并将其存储在某个地方,要么你应该确保在你的程序中永远不会在 vec 中推送任何新项目,或者请求更改其容量。或者风险分段错误...

    因此在你的例子中它导致

    vector.insert(pos, &vec[first_index], &vec[last_index]);
    

    【讨论】:

    • 让我想知道为什么他们决定抽象出迭代器,如果它们只是指针......它们本质上是“隐藏”这些功能。
    • 为了一致性?因为它可以让您轻松删除代码中任何其他类型容器的矢量实例。
    • &vec[i] 产生一个不一定与 vector::iterator 兼容的指针。 vec.begin()+i 仍然具有成为您的库定义的任何迭代器的好处——例如,包括在调试模式下检查的迭代器。所以,如果你不需要指针(例如用于 I/O),你应该总是更喜欢迭代器。
    • @KerrekSB 从 c++ 标准草案中的 23.3.6.1 开始:“向量的元素是连续存储的,这意味着如果 v 是向量 其中 T 是 bool 以外的其他类型,那么对于所有 0 ,它都服从恒等式 &v[n] == &v[0] + n
    • @yvesBaumes:这与向量迭代器无关。然而,裸指针确实是也是迭代器——它们只是不是vector迭代器。
    猜你喜欢
    • 2014-09-19
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多