C++ 获取std::vector迭代器索引的最有效方法是什么?

C++ 获取std::vector迭代器索引的最有效方法是什么?,c++,iterator,coding-style,C++,Iterator,Coding Style,我在一个向量上迭代,需要迭代器当前指向的索引。AFAIK这可以通过两种方式完成: it-vec.begin() 距离(vec.begin(),it) 这些方法的优缺点是什么?我喜欢这一种:it-vec.begin(),因为对我来说它清楚地表明了“从开始到结束的距离”。对于迭代器,我们习惯于用算术来思考,因此-符号是这里最清晰的指示器。我更喜欢std::distance(vec.begin(),it),因为它允许我在不更改任何代码的情况下更改容器。例如,如果您决定使用std::list而不是s

我在一个向量上迭代,需要迭代器当前指向的索引。AFAIK这可以通过两种方式完成:

  • it-vec.begin()
  • 距离(vec.begin(),it)

这些方法的优缺点是什么?

我喜欢这一种:
it-vec.begin()
,因为对我来说它清楚地表明了“从开始到结束的距离”。对于迭代器,我们习惯于用算术来思考,因此
-
符号是这里最清晰的指示器。

我更喜欢
std::distance(vec.begin(),it)
,因为它允许我在不更改任何代码的情况下更改容器。例如,如果您决定使用
std::list
而不是
std::vector
,后者不提供随机访问迭代器,您的代码仍将编译。由于std::distance根据迭代器的特性选择最佳方法,因此性能也不会下降。

根据,由于
vec.begin()
是一个随机访问迭代器,因此distance方法使用
-
运算符


因此,答案是,从性能角度来看,这是相同的,但是如果任何人都必须阅读和理解您的代码,那么使用
distance()
可能更容易理解。

我更喜欢
it-vec.begin()
正是因为Naveen给出的相反原因:因此,如果将向量更改为列表,它将无法编译。如果在每次迭代中都这样做,那么很容易将O(n)算法变成O(n^2)算法

另一种选择是,如果在迭代过程中不在容器中跳转,则将索引保留为第二个循环计数器


注意:
it
是容器迭代器的通用名称,
std::container\u type::iterator it

正如UncleBens和Naveen所展示的,这两者都有很好的理由。哪一个“更好”取决于您想要的行为:您想要保证恒定时间的行为,还是在必要时将其退回到线性时间

it-vec.begin()
需要固定的时间,但是
操作符-
仅在随机访问迭代器上定义,因此代码根本不会使用列表迭代器编译

std::distance(vec.begin(),it)
适用于所有迭代器类型,但仅在随机访问迭代器上使用时才是常量时间操作


两者都不是“更好”。使用能满足您需要的变量。

我只会使用
-
变量来表示
std::vector
——它的含义非常清楚,操作的简单性(不超过指针减法)由语法表示(
distance
,另一方面,听起来像是毕达哥拉斯的一读,不是吗?)。正如UncleBen指出的,
-
向量
意外更改为
列表
的情况下也充当静态断言


另外,我认为它更常见——虽然没有数字来证明它。主参数:
it-vec.begin()
的源代码更短—打字工作更少,占用的空间更少。很明显,问题的正确答案归结为品味问题,这也是一个有效的论点。

如果您已经限制/硬编码您的算法只使用
std::vector::iterator
std::vector::iterator
,你最终会使用哪种方法并不重要。你的算法已经具体化了,已经超出了选择另一种方法会产生任何影响的程度。它们都做完全相同的事情。这只是个人偏好的问题。我个人会使用显式减法

另一方面,如果您希望在算法中保留更高程度的通用性,即允许将来某一天它可能应用于其他迭代器类型,那么最佳方法取决于您的意图。这取决于您希望对此处可以使用的迭代器类型的限制程度。

  • 如果您使用显式减法,您的算法将局限于一个相当狭窄的迭代器类:随机访问迭代器。(这是您现在从
    std::vector
    获得的结果)

  • 如果您使用
    距离
    ,您的算法将支持更广泛的迭代器类:输入迭代器


当然,计算非随机访问迭代器的
距离
在一般情况下是一种低效的操作(而对于随机访问迭代器,它的效率与减法一样高)。由您决定您的算法对非随机访问迭代器的效率是否有意义。如果由此导致的效率损失是毁灭性的,以至于使您的算法完全无用,那么您最好坚持使用减法,从而禁止低效使用,并迫使用户寻求替代方案其他迭代器类型的改进。如果非随机访问迭代器的效率仍在可用范围内,则应使用
distance
,并记录该算法在随机访问迭代器中工作得更好的事实。

以下是查找“all”的示例与索引一起出现10次。认为这会有所帮助

void _find_all_test()
{
    vector<int> ints;
    int val;
    while(cin >> val) ints.push_back(val);

    vector<int>::iterator it;
    it = ints.begin();
    int count = ints.size();
    do
    {
        it = find(it,ints.end(), 10);//assuming 10 as search element
        cout << *it << " found at index " << count -(ints.end() - it) << endl;
    }while(++it != ints.end()); 
}
void\u find\u all\u test()
{
矢量整数;
int-val;
当(cin>>val)输入推回(val)时;
向量::迭代器;
it=ints.begin();
int count=int.size();
做
{
it=find(it,ints.end(),10);//假设10是搜索元素
我刚刚发现:

for(const auto&element:str | boost::adapters::index(0)){

std::cout除了int float string等,当使用不同类型时,您可以将额外的数据放到.second,例如:

std::map<unsigned long long int, glm::ivec2> voxels_corners;
std::map<unsigned long long int, glm::ivec2>::iterator it_corners;

使用正确的类型| |结构,您可以在.second中放置任何内容,包括ind
struct voxel_map {
    int x,i;
};

std::map<unsigned long long int, voxel_map> voxels_corners;
std::map<unsigned long long int, voxel_map>::iterator it_corners;
long long unsigned int index_first=some_key; // llu in this case...
int i=0;
voxels_corners.insert(std::make_pair(index_first,glm::ivec2(1,i++)));
long long unsigned int index_first=some_key;
int index_counter=0;
voxel_map one;
one.x=1;
one.i=index_counter++;

voxels_corners.insert(std::make_pair(index_first,one));
it_corners - _corners.begin()
std::distance(it_corners.begin(), it_corners)
it_corners = voxels_corners.find(index_first+bdif_x+x_z);
int vertice_index = it_corners->second.y;
int vertice_index = it_corners->second.i;