【问题标题】:Obtain iterator from pointer or reference从指针或引用中获取迭代器
【发布时间】:2016-09-03 05:56:25
【问题描述】:

我想知道是否可以通过仅访问容器内的对象来获取容器内对象的迭代器(例如std::vector<...>),例如通过引用(这意味着我们可以使用& 运算符访问指向它的指针)。例如,通常我们将迭代器声明为

std::vector<int>::iterator = vec.begin();

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

但是在第一个示例中,我们很可能要按顺序遍历容器,而在第二个示例中,我们知道我们需要的对象的索引。我想知道我们是否可以在不知道对象驻留在容器中哪个索引处的情况下获取对象的迭代器,但如果我们确实有一个引用或指向它的指针,如上所述。

似乎这个问题已经被问过here,但看起来更像是 OP 希望其他人修复他的代码,而不是回答一般问题,所以我认为答案并不那么令人满意。还有here的回答好像说我们可以用构造函数初始化迭代器,如下图

std::vector<int>::iterator it(...);

但我无法在官方文档中找到 std::iterator 类的构造函数的任何证据(我也无法在 std::vector<...>:: 上找到任何文档iterator) 所以我很谨慎地使用上面显示的构造函数,即使它可以编译。

注意

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

【问题讨论】:

  • 你可以浏览一个索引。 vec.begin()+(pos-&amp;vec[0])
  • @KonradKapp 那么你应该寻找关于如何找到索引的问题;-)
  • @dyp 是的,很抱歉第一次不清楚。我在问题中添加了注释。我更喜欢使用迭代器,因为我希望将它用作 for 循环中的中断条件。但这无关紧要:)问题更普遍的是关于是否可以以这种方式获得迭代器(不过,这似乎应该很容易)
  • 调试迭代器实现可能希望在迭代器中存储指向某个簿记对象的指针;在这种情况下,可能无法仅从元素的引用或指针构造迭代器(因为元素的位置和簿记对象的位置不相关)。当然,总是可以实现一些全局 LUT,但这很快就会变得丑陋/缓慢。
  • 由于迭代器的类型很多,您不太可能找到一种统一的方法来解决所有这些问题。当然,您可以只创建您选择的迭代器并进行迭代,直到它与您的给定项目匹配。

标签: c++ pointers iterator containers


【解决方案1】:

特别是对于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; });

对于 intrusive 容器,迭代器将以某种方式被编码到对象本身中,因此将有一些直接的机制将p 转换为迭代器。但这将取决于侵入式容器本身。

【讨论】:

  • 但是请注意,即使对于连续的数据结构,您也需要知道 哪个 容器确实包含该对象。尝试使用指向驻留在不同容器中的对象(或根本没有)的指针来恢复迭代器将失败。
  • @DietmarKühl 要清楚,当你说 which 容器时,你实际上是指容器的 type ,(如它是否是 @987654329 @、listdeque,例如),而不是容器的哪个 instance? (例如在vector的实例之间?)
  • @KonradKapp 他指的是哪个实例。
  • @KonradKapp 不,你需要知道你需要在什么实例上调用begin
  • @KonradKapp: 我的意思是 instance: 如果你有两个向量,v1v2 并且你的指针(或引用)p 指向一个元素在其中一个中,您需要知道元素指向两个容器中的哪一个。除非p 处于半开范围v.data()v.data() + v.size(),否则操作std::distance(v.data(), p) 是未定义的。
【解决方案2】:

您可以使用find 函数---它返回一个迭代器---(几乎?)所有容器都支持,来查找您的对象。如果operator==下有多个相等的对象,则迭代直到找到具有相同地址的对象。

【讨论】:

    【解决方案3】:

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

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

    如果我们不知道索引,我们可以使用 begin 中的 std::distance() 和另一个迭代器,这将为我们提供指向同一元素的迭代器。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多