ChatGPT解决这个技术问题 Extra ChatGPT

C++ STL 向量:从索引中获取迭代器?

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

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

d
dirkgently

尝试这个:

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

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

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

还; 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:如果复制迭代器是性能问题,那么您需要处理更大的问题。
S
SRG

您始终可以使用 std::advance 在恒定时间内将迭代器移动一定数量的位置:

std::vector<int>::iterator it = myvector.begin();
std::advance(it, 2);

y
yves Baumes

实际上 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 是 vector ,其中 T 是 bool 以外的某种类型,那么它遵循身份 &v[ n] == &v[0] + n 对于所有 0 <= n < v.size()"
@yvesBaumes:这与向量迭代器无关。然而,裸指针确实也是迭代器——它们只是不是向量迭代器。