从指针或引用获取迭代器

10
我想知道是否有可能通过仅访问容器内部的对象(例如std :: vector <...>)来获得一个迭代器, 例如通过引用(这意味着我们可以使用&运算符访问其指针)。例如,通常我们声明一个迭代器为
std::vector<int>::iterator = vec.begin();

或者
std::vector<int>::iterator = next(vec.begin(), idx);

但在第一个示例中,我们很可能会按顺序遍历容器,而在第二个示例中,我们知道我们需要的对象的索引。我想知道是否可以在不知道对象在容器中的索引的情况下获得对该对象的迭代器,但如果我们确实有对它的引用或指针,则如上所述。
这个问题似乎已经被问过了,见这里,但似乎更像是OP希望别人修复他的代码,而不是回答一般性问题,因此答案在我看来并不令人满意。此外,这里的答案似乎表明我们可以使用构造函数初始化迭代器,如下所示。
std::vector<int>::iterator it(...);

但我在官方文档中没有找到std :: iterator类的构造函数证据(我也没有找到有关std :: vector< ... > :: iterator的文档),因此即使它编译通过,我仍然不敢使用上面显示的构造函数。

注意

我以上使用std :: vector作为示例,但理想情况下,我希望这适用于任何容器,例如std :: liststd :: deque


1
你可以通过索引来遍历。vec.begin()+(pos-&vec[0]) - Marc Glisse
@KonradKapp 那你应该寻找如何查找索引的问题;-) - Marc Glisse
@dyp 是的,抱歉第一次没有表达清楚。我在问题中添加了一个注释。我更喜欢使用迭代器,因为我希望将其用作 for 循环中的 break 条件。但这并不是重点 :) 问题更普遍地涉及是否可以以这种方式获取迭代器(虽然这似乎应该很容易)。 - Konrad
1
一个调试迭代器实现可能想要在迭代器中存储指向某个簿记对象的指针;在这种情况下,仅从元素的引用或指针构造迭代器可能是不可能的(因为元素的位置和簿记对象的位置是无关的)。当然,可以始终实现一些全局LUT,但这会很快变得丑陋/缓慢。 - dyp
由于存在许多类型的迭代器,因此很难找到一个统一的方法来解决所有问题。当然,您可以创建所需的迭代器,并进行迭代,直至找到匹配您给定项的地方。 - Eiko
显示剩余2条评论
3个回答

15

对于std::vector(以及其他连续容器,如std::string),给定指向向量中对象的指针p,我们可以简单地执行以下操作:

auto iter = v.begin() + std::distance(v.data(), p);

这是由连续性约定保证的。请注意,在这里随机访问是不足够的,上面的方法对于 std::deque 将无法工作。

对于任何其他容器,都没有简单的方法来实现这一点。您只能使用 find_if

auto iter = std::find_if(c.begin(), c.end(), [p](auto const& o) { return &o == p; });

对于内存侵入式容器,迭代器将被编码到对象本身中,所以将有一些直接的机制将p转换为迭代器。但这将取决于具体的内存侵入式容器。


请注意,即使对于连续的数据结构,您也需要知道哪个容器包含该对象。尝试使用指向驻留在不同容器中(或根本没有)的对象的指针来恢复迭代器将失败。 - Dietmar Kühl
@DietmarKühl,您的意思是说“哪个”容器时,实际上指的是哪种类型的容器(例如vectorlistdeque),而不是容器的哪个实例?(例如在vector的实例之间)?请澄清一下。 - Konrad
@KonradKapp 他的意思是哪个实例。 - Barry
@KonradKapp 不,你需要知道在哪个实例上调用 begin - Revolver_Ocelot
1
@KonradKapp:我的意思是_instance_:如果你有两个向量v1v2,并且你的指针(或引用)p指向其中一个元素,那么你需要知道元素指向哪个容器。除非p在半开范围v.data()v.data() + v.size()中,否则操作std::distance(v.data(), p)是未定义的。 - Dietmar Kühl
@DietmarKühl 是的,同意。我那时有点傻。 - Konrad

3
你可以使用find函数——它返回一个迭代器——在(几乎?)所有容器上进行支持,以查找你的对象。如果有多个对象在operator==下相等,请迭代直到找到具有相同地址的对象为止。

0

自从C++11以来,您可以使用关键字auto来推断类型,这使得编写类型更加容易。

如果我们知道索引,我们可以通过begin() + index获得迭代器。

如果我们不知道索引,我们可以使用{{link1:std::distance()}}从begin和另一个迭代器获取迭代器,这将给我们一个指向相同元素的迭代器。

// if we know the index
auto it1 = begin(vec) + 4;
cout << *it1;

// if we don't know the index
auto p = begin(vec) + 3;
auto it2 = begin(vec) + distance(begin(vec), p+1);
cout << *it2;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接