我如何得到一个std::vector的迭代器的索引?

我正在迭代一个向量,需要迭代器当前指向的下标。下列方法的优缺点是什么?

  • # EYZ0
  • # EYZ0
419907 次浏览

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

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

根据http://www.cplusplus.com/reference/std/iterator/distance/,由于vec.begin()随机存取迭代器,距离方法使用-操作符。

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

我更喜欢it - vec.begin(),正是因为Naveen给出的相反原因:所以如果你把矢量变成一个列表,它会编译不会。如果你在每次迭代中都这样做,你可以很容易地把O(n)算法变成O(n²)算法。

另一种选择是,如果在迭代期间不在容器中跳来跳去,则将索引保留为第二个循环计数器。

注意:it是容器迭代器std::container_type::iterator it;的常用名称。

正如本叔叔和内文所表明的那样,两者都有很好的理由。哪一种“更好”取决于您想要的行为:您是希望保证常量时间行为,还是希望在必要时回落到线性时间?

it - vec.begin()花费常数时间,但operator -只在随机访问迭代器上定义,因此,例如,使用列表迭代器时,代码根本无法编译。

std::distance(vec.begin(), it)适用于所有类型的迭代器,但如果用于随机访问迭代器,则只有常量时间操作。

两者都不是“更好”。用你需要的那个。

我只会对std::vector使用-变体——它的意思非常清楚,操作的简单性(这不仅仅是一个指针减法)是通过语法来表达的(另一方面,distance在第一次阅读时听起来像毕达哥拉斯,不是吗?)正如UncleBen指出的那样,-还充当一个静态断言,以防vector意外地更改为list

我也认为这是更普遍的-虽然没有数字可以证明。主参数:it - vec.begin()在源代码中更短-更少的输入工作,更少的空间消耗。很明显,你的问题的正确答案归结为一个品味的问题,可以是一个有效的论点。

如果你已经限制/硬编码你的算法只使用std::vector::iteratorstd::vector::iterator,那么你最终使用哪种方法并不重要。你的算法已经具体化了,选择其中一个会有任何不同。它们做的事情完全一样。这只是个人喜好的问题。我个人会使用显式减法。

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

  • 如果使用显式减法,则算法将被限制在相当狭窄的一类迭代器中:随机访问迭代器。(这是你现在从std::vector中得到的)

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

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

我刚刚发现了这个:https://greek0.net/boost-range/boost-adaptors-indexed.html

    for (const auto & element : str | boost::adaptors::indexed(0)) {
std::cout << element.index()
<< " : "
<< element.value()
<< std::endl;
}


除了int float string等,当使用div . types时,你可以将额外的数据放入.second,例如:

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

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));

使用正确的||结构,你可以把任何东西放在。second中,包括在进行插入时递增的索引号。

而不是

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;

当使用glm::ivec2类型时

int vertice_index = it_corners->second.i;

对于结构数据类型