【问题标题】:STL iterator: "dereferencing" iterator to a temporary. Is it possible?STL 迭代器:将迭代器“取消引用”到临时。可能吗?
【发布时间】:2011-05-02 07:33:16
【问题描述】:

我正在为我的科学软件编写一个 3D 网格,我需要遍历网格的节点以获取它们的坐标。我宁愿在迭代时动态计算坐标,而不是将每个节点对象保存在容器中。问题是 stl::iterator 需要返回对值的引用作为 operator*() 的结果,或 operator->() 的指针。

部分代码如下:


class spGridIterator {
public:
    typedef forward_iterator_tag iterator_category;
    typedef spVector3D value_type;
    typedef int difference_type;
    typedef spVector3D* pointer;
    typedef spVector3D& reference;

    spGridIterator(spGrid* gr, int index);

    spGridIterator& operator++();
    spGridIterator& operator++(int);

    reference operator*() const;
    pointer operator->() const;

private:
    spGrid* m_grid;
    int m_idx;
};

spGridIterator::reference spGridIterator::operator*() const {
    // return m_grid->GetPoint(m_idx);
}

spGridIterator::pointer spGridIterator::operator->() const {
    // return m_grid->GetPoint(m_idx);
}

该方法通过提供的索引查询节点坐标


spVector3D spGrid::GetPoint(int idx) const {
    // spVector3D vec = ... calculate the coordinates here ...
    return vec;
}

对此有何意见?

提前致谢, 伊利亚

【问题讨论】:

  • "问题在于 stl::iterator 需要返回对值的引用作为 operator*() 的结果,或者 operator->() 的指针" 为什么这是个问题?为了什么?
  • 我不确定我是否真正理解您想要实现的目标。也许您可以包含一个客户端代码示例,以了解您如何尝试使用此集合。
  • “为什么会有问题?为什么?”因为这种方式我不得不保留一个实际变量来指向(或引用)。
  • 我需要迭代器来取消对临时变量的引用,因为节点坐标应该是动态计算的,而不是存储在某个地方。

标签: c++ stl iterator


【解决方案1】:

你可以使用一个成员变量来保存它当前指向的网格点:

class spGridIterator {
public:
    typedef forward_iterator_tag iterator_category;
    typedef spVector3D value_type;
    typedef int difference_type;
    typedef spVector3D* pointer;
    typedef const spVector3D* const_pointer;
    typedef const spVector3D& const_reference;
    typedef spVector3D& reference;

    spGridIterator(spGrid* gr, int index);

    spGridIterator& operator++();
    spGridIterator& operator++(int);

    reference operator*();
    const_reference operator*() const;

    pointer operator->();
    const_pointer operator->() const;

private:
    spGrid* m_grid;
    int m_idx;
    mutable spVector3D CurrentPoint;
};

那么解引用操作符可能如下所示:

spGridIterator::const_reference spGridIterator::operator*() const {
    CurrentPoint = m_grid->GetPoint(m_idx);
    return CurrentPoint;
}

感谢@greg 指出CurrentPoint 需要mutable 才能工作。这将是一个惰性实现(仅在迭代器实际被取消引用时检索该点)。急切的实现会更新迭代器的 mutator 方法中的 CurrentPoint 成员(本示例中的 operator++ 变体),从而使 mutable 变得多余。

【讨论】:

  • 除非CurrentPointmutable,否则operator*() 不能是const,对吗?
  • 没错,这没有意义。我确定了答案。
  • 这仍然不太正确,因为您无法从const 方法中更改spGridIterator 对象的状态。 CurrentPointoperator*() 中的赋值不会编译,除非 CurrentPointmutable
  • 正确,我真的不应该在没有编译器的情况下编写代码。我现在修复了它并添加了一些解释。希望现在是正确的,感谢您的输入。
  • 感谢您的更新。关于在operator++() 等中进行分配的一个注意事项是,如果没有mutable,我认为您将无法拥有const spGridIteratorconst_iterator 类型关闭容器)。跨度>
【解决方案2】:

我知道这篇文章太旧了,但只是因为我有同样的“问题” 和谷歌把我带到这里,我会加我的两分钱,这是我发现的:

至少在 C++ 库中有很多迭代器类型,每一种都声明了一些相关的语义。类型是

  • 输入迭代器
  • 前向迭代器
  • 双向迭代器
  • 随机访问迭代器
  • 输出迭代器

在您的问题情况下,输入迭代器语义适合。特别是在输入迭代器中operator*() 不必返回对对象的引用,它甚至可以返回新创建的对象。从而避免像 Bjorn 建议的那样在迭代器对象中包含一个“虚拟”对象。

您可以查看更多here

【讨论】:

    【解决方案3】:

    既然迭代器是一个值对象,为什么不把一个成员设置为你想要返回的值,然后返回一个对成员的引用呢?

    【讨论】:

      【解决方案4】:

      简短的回答是,这将导致未定义的行为,毕竟您返回的是对临时的引用!一种选择(如果此迭代器不必重入)是拥有一个类成员(spVector3D 类型),您“分配”返回的值(当然,您可以通过传入对 this 的引用来更优化地做到这一点GetPoint 以及 index),然后返回。

      【讨论】:

      • 也感谢您的回复!
      猜你喜欢
      • 1970-01-01
      • 2015-01-13
      • 2015-09-26
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 2018-09-02
      • 2014-12-26
      相关资源
      最近更新 更多