在不使用vector.end()的情况下迭代std::vector

Iterate std::vector without using vector.end()

本文关键字:vector 情况下 迭代 std end      更新时间:2023-10-16

C++菜鸟。我写了一个函数,从向量返回迭代器,我想使用这个迭代器从头到尾迭代向量。然而,向量迭代器的使用方式与类似

for (auto iterator = vec.begin(); iterator != vec.end(); iterator ++) {
// do something here
}

这意味着我还需要一个vec.end()来实现这一点。不管怎样,我只能使用vec.begin()来迭代一个向量,就像我在python 中经常做的那样

for value in some_iterator:
# do something

编辑:一些无关的更新:

我看到一些关于我的python迭代器与iterable的评论。迭代器确实可以这样使用(至少在Python3中是这样)。例如:

some_list = [1,2,3,4]
some_iterator = iter(some_list)
for value in some_iterator:
print(value)

C++不是Python。需要std::vector::iterators的来表示范围(开始和一个超过结束)。如果你只有一个迭代器,那么你就无法安全地使用它(除了将它与本身进行比较,后者是空洞的true)。

您混淆了python可迭代的python概念,它是一个值序列。这与Python迭代器不同,后者是一个具有next()(Python3中的__next__())的对象,返回下一个值或抛出StopIteration

for value in some_iterable:
#do something here

大致对应

_iter = some_iterable.__iter__()
while True:
try
value = _iter.__next__()
except StopIteration:
break;
#do something here

你可能想要一个针对声明的范围

for (auto val : vec){
// do something here
}

大致对应

{
auto && __range = vec; 
for (auto __begin = begin(__range), __end = end(__range);  __begin != __end; ++__begin) { 
auto val = *__begin; 
// do something here
} 
} 

(在这两个版本中,以_开头的局部变量实际上并不存在,名称是解释性的)

C++迭代器将返回的值(*itit->)从移动(++it等)中分离出来;以及从停止(it != end)开始,其中end指向最后元素一个。Python迭代器在next()中完成所有任务。

正如其他人已经指出的那样:

for value in some_iterator:
# do something

不正确:您在数组中进行迭代,或者更一般地说,在"可迭代"中,通过使用它的内部__iter__迭代器进行迭代。所以它更正确:

for value in some_iterable:
# do something

python中的可伸缩性是C++中的"容器"。std::vector是一个容器。

我认为你有两个选择:

  • 如果你想拥有完整的容器("从头至尾",所以我想是这样),只需返回它。如果函数退出后它的寿命继续,你可以通过引用返回它:事实上,在python中,数组是通过引用复制的,所以这是等效的。然而,如果它是一个临时向量,您可以按值返回它,但不要担心它会被复制:使用现代C++和std::move运算符,这是不会发生的

"旧方法"是通过引用函数来传递一个空向量,并让函数填充该向量。

  • 如果你想返回一个范围,你可以返回一对迭代器。例如,您可以模拟std::multimap<>::equal_range()返回

然而,我通常不喜欢将std::pair用于此类操作,而是为了特定的目的伪造我的临时类型。

例如,这可能是您的函数的签名:

template<typename TYPE>
struct GetRangeResult {
std::vector<TYPE>::const_iterator begin;
std::vector<TYPE>::const_iterator end;
};
template<typename TYPE>
GetRangeResult<TYPE> GetRange(/* your args */) {
GetRangeResult<TYPE> result;
// the method here fills result.begin and result.end
return result;
}

你会用它:

auto range = GetRange(/* your args */);
for (auto it=range.begin; it!=range.end; ++it) {
...
}

同样,如果矢量在GetRange()函数中是临时的,则不能执行此操作。

我写了一个函数,从向量返回迭代器,我想使用这个迭代器从头到尾迭代向量。

您需要两个迭代器来遍历容器——起始迭代器和结束迭代器。例如,更改函数以返回迭代器的std::pair,而不是单个迭代器,然后就可以进行迭代,例如:

template<typename Container>
std::pair<Container::iterator, Container::iterator> func(Container &c) {
return std::make_pair(c.begin(), c.end());
}
auto p = func(vec);
for (auto iter = p.first; iter != p.second; ++iter) {
// do something here
}

无论如何,我只能使用vec.begin()迭代通过向量吗

否。如果没有第二个迭代器,您将不知道何时停止迭代。

就像我在python 中经常做的那样

最接近这一点的是一个基于范围的for循环,但这需要访问向量本身,它手动使用迭代器(循环内部使用迭代程序):

for (auto &elem : vec) {
// do something here
}

没有办法从迭代器获取对原始容器的引用。这意味着,如果你有一个函数,比如说,将迭代器返回到向量的中点,那么它实际上是无用的,除非你知道它来自哪个向量。

您的选择是:

  1. 只有当您可以访问正在操作的向量时才使用该函数(用法类似于std::find)
  2. 从函数返回一组迭代器,指定要迭代的范围
  3. 从函数返回一个对原始向量的引用,旁边还有一个迭代器,表示要迭代到/从中迭代的偏移量

如果不知道函数的用途,很难给出更具体的建议。我怀疑可能还有更好的方法来构建代码。

相关文章: